Railway Operation Simulator  v2.23.1
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 /*
2  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
3  sometimes been overtaken by changes and not updated
4  Comments in .h files are believed to be accurate and up to date
5 
6  This is a source code file for "railway.exe", a railway operation
7  simulator, written originally in Borland C++ Builder 4 Professional with
8  later updates in Embarcadero C++Builder.
9  Copyright (C) 2010 Albert Ball [original development]
10 
11  This program is free software: you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24 // ---------------------------------------------------------------------------
25 #include <Classes.hpp>
26 #include <Controls.hpp>
27 #include <StdCtrls.hpp>
28 #include <Forms.hpp>
29 #include <Buttons.hpp>
30 #include <ExtCtrls.hpp>
31 #include <Menus.hpp>
32 #include <Dialogs.hpp>
33 #include <Graphics.hpp>
34 #include <ComCtrls.hpp>
35 #include <fstream>
36 #include <vector>
37 #include <algorithm> //for std::find
38 #include <vcl.h>
39 #include <windows.h>
40 #pragma hdrstop
41 
42 #include "TrackUnit.h"
43 #include "TrainUnit.h"
44 #include "GraphicUnit.h"
45 //#include "DisplayUnit.h" included in TrackUnit.h
46 #include "TextUnit.h"
47 #include "PerfLogUnit.h"
48 #include "Utilities.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  //deal with TSRs
226  if((TrackType == Simple) && Failed) //added at v2.13.0
227  {
228  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
229  }
230  Utilities->CallLogPop(1332);
231 }
232 
233 // ---------------------------------------------------------------------------
234 
235 AnsiString TTrackElement::LogTrack(int Caller) const
236 // for debugging when passes as a call parameter
237 {
238  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
239  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
240 
241  return(LogString);
242 }
243 
244 // ---------------------------------------------------------------------------
245 
247  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
248  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
249  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1),
250  StationEntryStopLinkPos2(-1), StationEntryStopLinkPos3(-1), StationEntryStopLinkPos4(-1), SigAspect(FourAspect)
251  {
252  Failed = false; //added at v2.13.0
253  for(int x = 0; x < 4; x++)
254  {
255  ConnLinkPos[x] = -1;
256  Conn[x] = -1;
257  }
258  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
259  {
262  }
263  }
264 
265 // ---------------------------------------------------------------------------
266 
267 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
268 {
269  if(lower.second < higher.second)
270  {
271  return(true);
272  }
273  else if(lower.second > higher.second)
274  {
275  return(false);
276  }
277  else if(lower.second == higher.second)
278  {
279  if(lower.first < higher.first)
280  {
281  return(true);
282  }
283  }
284  return(false);
285 }
286 
287 // ---------------------------------------------------------------------------
288 // PrefDirElement Functions
289 // ---------------------------------------------------------------------------
290 
291 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
292  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
293  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
294 {
295  if(!EntryExitNumber())
296  {
297  throw Exception("EXNumber failure in TPrefDirElement constructor");
298  }
301 }
302 
303 // ---------------------------------------------------------------------------
304 
305 AnsiString TPrefDirElement::LogPrefDir() const
306 // for debugging when passed as a call parameter
307 {
308  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
309  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
310  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
312 
313 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
314  return(LogString);
315 }
316 
317 // ---------------------------------------------------------------------------
318 
319 bool TPrefDirElement::EntryExitNumber() // true for valid number
320 /*
321  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
322  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
323  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
324  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
325  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
326  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
327  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
328  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
329  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
330 */
331 
332 {
333  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
334  int EXArray[16][2] =
335  {{4, 6}, {2, 8}, // horizontal & vertical
336  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
337  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
338  {1, 9}, {3, 7}}; // forward & reverse diagonals
339 
340  int EXNum = -1;
341  int Entry, Exit;
342 
343  if(ELink > -1)
344  {
345  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
346  }
347  else if(Link[2] == -1)
348  {
349  Entry = Link[0];
350  }
351  else
352  {
353  Utilities->CallLogPop(122);
354  return(false);
355  }
356  if(XLink > -1)
357  {
358  Exit = XLink;
359  }
360  else if(Link[2] == -1)
361  {
362  Exit = Link[1];
363  }
364  else
365  {
366  Utilities->CallLogPop(123);
367  return(false);
368  }
369  for(int x = 0; x < 16; x++)
370  {
371  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
372  {
373  EXNum = x;
374  }
375  }
376  if(EXNum == -1)
377  {
378  Utilities->CallLogPop(124);
379  return(false);
380  }
381  int BrNum = -1;
382 
383 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
384  the graphic for each of which is different because of the shape of the overbridge. The basic
385  entry/exit value is computed above, and this used to select only from elements with that entry/exit
386  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
387  int BrEXArray[24][2] = {
388  {4,6},{2,8},{1,9},{3,7},
389  {1,9},{3,7},{1,9},{3,7},
390  {2,8},{4,6},{2,8},{4,6}
391 */
392 
393  if(TrackType == Bridge)
394  {
395  if(EXNum == 1)
396  {
397  if(SpeedTag == 49)
398  {
399  BrNum = 1 + 16;
400  }
401  else if(SpeedTag == 54)
402  {
403  BrNum = 8 + 16;
404  }
405  else if(SpeedTag == 55)
406  {
407  BrNum = 10 + 16;
408  }
409  }
410  else if(EXNum == 0)
411  {
412  if(SpeedTag == 48)
413  {
414  BrNum = 0 + 16;
415  }
416  else if(SpeedTag == 58)
417  {
418  BrNum = 11 + 16;
419  }
420  else if(SpeedTag == 59)
421  {
422  BrNum = 9 + 16;
423  }
424  }
425  else if(EXNum == 14)
426  {
427  if(SpeedTag == 50)
428  {
429  BrNum = 2 + 16;
430  }
431  else if(SpeedTag == 52)
432  {
433  BrNum = 4 + 16;
434  }
435  else if(SpeedTag == 57)
436  {
437  BrNum = 6 + 16;
438  }
439  }
440  else if(EXNum == 15)
441  {
442  if(SpeedTag == 51)
443  {
444  BrNum = 3 + 16;
445  }
446  else if(SpeedTag == 53)
447  {
448  BrNum = 7 + 16;
449  }
450  else if(SpeedTag == 56)
451  {
452  BrNum = 5 + 16;
453  }
454  }
455  }
456  if(BrNum == -1)
457  {
458  EXNumber = EXNum;
459  }
460  else
461  {
462  EXNumber = BrNum;
463  }
464  Utilities->CallLogPop(125);
465  return(true);
466 }
467 
468 // ---------------------------------------------------------------------------
469 
471 /*
472  This is the basic track graphic for use in plotting the original graphic during route flashing.
473  Enter with all set apart from EXGraphic & EntryDirectionGraphic
474 */
475 {
476  if(SpeedTag == 64)
477  {
478  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
479 
480  }
481  if(SpeedTag == 65)
482  {
483  return(RailGraphics->LinkGraphicsPtr[17]);
484  }
485  if(SpeedTag == 66)
486  {
487  return(RailGraphics->LinkGraphicsPtr[18]);
488  }
489  if(SpeedTag == 67)
490  {
491  return(RailGraphics->LinkGraphicsPtr[19]);
492  }
493  if(SpeedTag == 80)
494  {
495  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
496 
497  }
498  if(SpeedTag == 81)
499  {
500  return(RailGraphics->LinkGraphicsPtr[21]);
501  }
502  if(SpeedTag == 82)
503  {
504  return(RailGraphics->LinkGraphicsPtr[22]);
505  }
506  if(SpeedTag == 83)
507  {
508  return(RailGraphics->LinkGraphicsPtr[23]);
509  }
510  if(SpeedTag == 84)
511  {
512  return(RailGraphics->LinkGraphicsPtr[24]);
513  }
514  if(SpeedTag == 85)
515  {
516  return(RailGraphics->LinkGraphicsPtr[25]);
517  }
518  if(SpeedTag == 86)
519  {
520  return(RailGraphics->LinkGraphicsPtr[26]);
521  }
522  if(SpeedTag == 87)
523  {
524  return(RailGraphics->LinkGraphicsPtr[27]);
525  }
526  if(SpeedTag == 129)
527  {
528  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
529 
530  }
531  if(SpeedTag == 130)
532  {
533  return(RailGraphics->LinkGraphicsPtr[29]);
534  }
535  if(XLinkPos == -1) // not set, could be first element or last element = leading point
536  {
537 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
538 // Points & don't want to display these)
539  if(Link[2] != -1)
540  {
541  return(0); // i.e. complex element, don't display
542  }
543  else
544  {
545  if(!EntryExitNumber())
546  {
547  throw Exception("Error in EntryExitNumber 4");
548  }
549  else
550  {
552  }
553  }
554  }
555  if(EXNumber > 15) // underbridge
556  {
557  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
558  }
559  else
560  {
562  }
563 }
564 
565 // ---------------------------------------------------------------------------
566 
568 /*
569  As above but for PrefDir graphics.
570 */
571 {
572  if(SpeedTag == 64)
573  {
574  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
575 
576  }
577  if(SpeedTag == 65)
578  {
580  }
581  if(SpeedTag == 66)
582  {
584  }
585  if(SpeedTag == 67)
586  {
588  }
589  if(SpeedTag == 80)
590  {
591  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
592 
593  }
594  if(SpeedTag == 81)
595  {
597  }
598  if(SpeedTag == 82)
599  {
601  }
602  if(SpeedTag == 83)
603  {
605  }
606  if(SpeedTag == 84)
607  {
609  }
610  if(SpeedTag == 85)
611  {
613  }
614  if(SpeedTag == 86)
615  {
617  }
618  if(SpeedTag == 87)
619  {
621  }
622  if(SpeedTag == 129)
623  {
624  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
625 
626  }
627  if(SpeedTag == 130)
628  {
630  }
631  if(XLinkPos == -1) // not set, could be first element or last element = leading point
632  {
633 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
634  if(Link[2] != -1)
635  {
636  return(0); // i.e. complex element, don't display
637  }
638  else
639  {
640  if(!EntryExitNumber())
641  {
642  throw Exception("Error in EntryExitNumber 5");
643  }
644  else
645  {
647  }
648  }
649  }
650  if(EXNumber > 15) // underbridge
651  {
653  }
654  else
655  {
657  }
658 }
659 
660 // ---------------------------------------------------------------------------
661 
662 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
663 /*
664  As above but for route graphics.
665 */
666 {
667  if(!AutoSigsFlag && !PrefDirRoute)
668  {
669  if(SpeedTag == 64)
670  {
671  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
672  }
673  if(SpeedTag == 65)
674  {
676  }
677  if(SpeedTag == 66)
678  {
680  }
681  if(SpeedTag == 67)
682  {
684  }
685  if(SpeedTag == 80)
686  {
687  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
688  }
689  if(SpeedTag == 81)
690  {
692  }
693  if(SpeedTag == 82)
694  {
696  }
697  if(SpeedTag == 83)
698  {
700  }
701  if(SpeedTag == 84)
702  {
704  }
705  if(SpeedTag == 85)
706  {
708  }
709  if(SpeedTag == 86)
710  {
712  }
713  if(SpeedTag == 87)
714  {
716  }
717  if(SpeedTag == 129)
718  {
719  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
720  }
721  if(SpeedTag == 130)
722  {
724  }
725  if(XLinkPos == -1) // not set, could be first element or last element = leading point
726  {
727  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
728  if(Link[2] != -1)
729  {
730  return(0); // i.e. complex element, don't display
731  }
732  else
733  {
734  if(!EntryExitNumber())
735  {
736  throw Exception("Error in EntryExitNumber 6");
737  }
738  else
739  {
741  }
742  }
743  }
744  if(EXNumber > 15) // underbridge
745  {
747  }
748  else
749  {
751  }
752  }
753 
754  else if(!AutoSigsFlag && PrefDirRoute)
755  {
756  if(SpeedTag == 64)
757  {
758  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
759  }
760  if(SpeedTag == 65)
761  {
763  }
764  if(SpeedTag == 66)
765  {
767  }
768  if(SpeedTag == 67)
769  {
771  }
772  if(SpeedTag == 80)
773  {
774  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
775  }
776  if(SpeedTag == 81)
777  {
779  }
780  if(SpeedTag == 82)
781  {
783  }
784  if(SpeedTag == 83)
785  {
787  }
788  if(SpeedTag == 84)
789  {
791  }
792  if(SpeedTag == 85)
793  {
795  }
796  if(SpeedTag == 86)
797  {
799  }
800  if(SpeedTag == 87)
801  {
803  }
804  if(SpeedTag == 129)
805  {
806  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
807  }
808  if(SpeedTag == 130)
809  {
811  }
812  if(XLinkPos == -1) // not set, could be first element or last element = leading point
813  {
814  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
815  if(Link[2] != -1)
816  {
817  return(0); // i.e. complex element, don't display
818  }
819  else
820  {
821  if(!EntryExitNumber())
822  {
823  throw Exception("Error in EntryExitNumber 10");
824  }
825  else
826  {
828  }
829  }
830  }
831  if(EXNumber > 15) // underbridge
832  {
834  }
835  else
836  {
838  }
839  }
840 
841  else
842  {
843  if(SpeedTag == 64)
844  {
845  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
846  }
847  if(SpeedTag == 65)
848  {
850  }
851  if(SpeedTag == 66)
852  {
854  }
855  if(SpeedTag == 67)
856  {
858  }
859  if(SpeedTag == 80)
860  {
861  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
862 
863  }
864  if(SpeedTag == 81)
865  {
867  }
868  if(SpeedTag == 82)
869  {
871  }
872  if(SpeedTag == 83)
873  {
875  }
876  if(SpeedTag == 84)
877  {
879  }
880  if(SpeedTag == 85)
881  {
883  }
884  if(SpeedTag == 86)
885  {
887  }
888  if(SpeedTag == 87)
889  {
891  }
892  if(SpeedTag == 129)
893  {
894  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
895 
896  }
897  if(SpeedTag == 130)
898  {
900  }
901  if(XLinkPos == -1) // not set, could be first element or last element = leading point
902  {
903  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
904  if(Link[2] != -1)
905  {
906  return(0); // i.e. complex element, don't display
907  }
908  else
909  {
910  if(!EntryExitNumber())
911  {
912  throw Exception("Error in EntryExitNumber 11");
913  }
914  else
915  {
917  }
918  }
919  }
920  if(EXNumber > 15) // underbridge
921  {
923  }
924  else
925  {
927  }
928  }
929 }
930 
931 // ---------------------------------------------------------------------------
932 
934 /*
935  As above but for route flashing graphics. (Disused - now combined with above)
936 */
937 {
938  if(SpeedTag == 64)
939  {
940  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
941 
942  }
943  if(SpeedTag == 65)
944  {
946  }
947  if(SpeedTag == 66)
948  {
950  }
951  if(SpeedTag == 67)
952  {
954  }
955  if(SpeedTag == 80)
956  {
957  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
958 
959  }
960  if(SpeedTag == 81)
961  {
963  }
964  if(SpeedTag == 82)
965  {
967  }
968  if(SpeedTag == 83)
969  {
971  }
972  if(SpeedTag == 84)
973  {
975  }
976  if(SpeedTag == 85)
977  {
979  }
980  if(SpeedTag == 86)
981  {
983  }
984  if(SpeedTag == 87)
985  {
987  }
988  if(SpeedTag == 129)
989  {
990  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
991 
992  }
993  if(SpeedTag == 130)
994  {
996  }
997  if(XLinkPos == -1) // not set, could be first element or last element = leading point
998  {
999 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1000  if(Link[2] != -1)
1001  {
1002  return(0); // i.e. complex element, don't display
1003  }
1004  else
1005  {
1006  if(!EntryExitNumber())
1007  {
1008  throw Exception("Error in EntryExitNumber 7");
1009  }
1010  else
1011  {
1013  }
1014  }
1015  }
1016  if(EXNumber > 15) // underbridge
1017  {
1019  }
1020  else
1021  {
1023  }
1024 }
1025 
1026 // ---------------------------------------------------------------------------
1027 
1029 /*
1030  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1031 */
1032 {
1033  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1034  {
1036  }
1037  else
1038  {
1039  throw Exception("Error in EntryExitNumber 8");
1040  }
1041 }
1042 
1043 // ---------------------------------------------------------------------------
1044 
1045 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1046 /*
1047  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1048 */
1049 {
1050  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1051  {
1052  if(!AutoSigsFlag && !PrefDirRoute)
1053  {
1055  }
1056  else if(!AutoSigsFlag && PrefDirRoute)
1057  {
1059  }
1060  else
1061  {
1063  }
1064  }
1065  else
1066  {
1067  throw Exception("Error in EntryExitNumber 9");
1068  }
1069 }
1070 
1071 // ---------------------------------------------------------------------------
1072 
1074 /*
1075  Set == operator when TrackVectorPosition, ELink & XLink all same
1076 */
1077 {
1078  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1079  {
1080  return(true);
1081  }
1082  else
1083  {
1084  return(false);
1085  }
1086 }
1087 
1088 // ---------------------------------------------------------------------------
1089 
1091 /*
1092  Set != operator when any of TrackVectorPosition, ELink or XLink different
1093 */
1094 {
1095  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1096  {
1097  return(false);
1098  }
1099  else
1100  {
1101  return(true);
1102  }
1103 }
1104 
1105 // ---------------------------------------------------------------------------
1106 
1107 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1108 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1109  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1110  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1111  {
1112  Utilities->CallLogPop(2566);
1113  return(1);
1114  }
1115  if(GetRouteGraphicPtr(0,1) == EXG)
1116  {
1117  Utilities->CallLogPop(2567);
1118  return(2);
1119  }
1120  if(GetRouteGraphicPtr(1,0) == EXG)
1121  {
1122  Utilities->CallLogPop(2568);
1123  return(3);
1124  }
1125  if(GetRouteGraphicPtr(1,1) == EXG)
1126  {
1127  Utilities->CallLogPop(2569);
1128  return(3);
1129  }
1130  Utilities->CallLogPop(2570);
1131  return(0);
1132 }
1133 
1134 // ---------------------------------------------------------------------------
1135 // Track functions
1136 // ---------------------------------------------------------------------------
1137 
1138 // ---------------------------------------------------------------------------
1139 
1141 {
1142  TypeOfRoute = 0;
1143  ReducedTimePenalty = false;
1144  BarrierState = Up;
1145  ChangeDuration = 0.0;
1146  BaseElementSpeedTag = 1;
1147  HLoc = 0;
1148  VLoc = 0;
1149  StartTime = TDateTime(0);
1150 }
1151 
1152 // ---------------------------------------------------------------------------
1153 
1155 {
1156 // CurrentSpeedButtonTag = 0; //not assigned yet
1157 
1158  HLocMin = 2000000000;
1159  VLocMin = 2000000000;
1160  HLocMax = -2000000000;
1161  VLocMax = -2000000000;
1162  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1163  CopyFlag = false; // only true for copying, so names aren't copied
1164  AnsiString NL = '\n';
1165 
1166  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1167  "reachable but too far ahead or with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1168  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1169  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1170 
1175  LengthHeatMapFlag = false;
1176  SpeedHeatMapFlag = false;
1177 
1178  int InternalLinkCheckArray[9][2] =
1179  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1180 
1181 /* array of valid link values for 'old' location and 'new' location, where
1182  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1183 
1184  for(int x = 0; x < 9; x++)
1185  {
1186  for(int y = 0; y < 2; y++)
1187  {
1188  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1189  }
1190  }
1191 
1192 // Platform and default track element values
1193  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1194 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1195  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1196  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1197  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1198  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16 << 18 << 19 << 20 << 21 << 22 << 23 << 24
1199  << 25 << 26 << 27 << 28 << 29 << 30 << 31 << 32 << 33 << 34 << 35 << 36 << 37 << 38 << 39 << 40 << 41 << 42 << 43 << 44 << 45 << 46 << 47
1200  << 60 << 61 << 62 << 63 << 64 << 65 << 66 << 67 << 68 << 69 << 70 << 71 << 72 << 73 << 74 << 75 << 80 << 81 << 82 << 83 << 84 << 85 << 86
1201  << 87 << 125 << 126 << 127 << 128 << 132 << 133 << 134 << 135 << 136 << 137 << 138 << 139
1202  << 140 << 141 << 142 << 143; //prevent bridges, footcrossings, platforms, concourses, non-station named locs, parapets, level crossings & gaps
1203  //gaps cause a mass of problems as links not adjacent - interferes with cut/copy/paste & duplicate names found
1204  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1205 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1206 
1207  int HVArray[10][2] =
1208  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1209 
1210  for(int x = 0; x < 10; x++)
1211  {
1212  for(int y = 0; y < 2; y++)
1213  {
1214  LinkHVArray[x][y] = HVArray[x][y];
1215  }
1216  }
1217  TrackFinished = false;
1218 // DistancesSet = false;
1219 
1220  TSigElement TempSigTable[40] = // original four aspect
1221  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1222  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1223 
1224  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1225  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1226 
1229 
1230  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1231  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1232 
1233  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1234  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1235  {75, 4, RailGraphics->gl75}};
1236 
1237  for(int x = 0; x < 40; x++)
1238  {
1239  SigTable[x] = TempSigTable[x];
1240  }
1241 
1242  TSigElement TempSigTableThreeAspect[40] =
1243  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1244  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1245 
1246  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1247  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1248 
1249  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1250  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1251 
1252  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1253  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1254 
1255  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1256  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1257  {75, 4, RailGraphics->gl75}};
1258 
1259  for(int x = 0; x < 40; x++)
1260  {
1261  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1262  }
1263 
1264  TSigElement TempSigTableTwoAspect[40] =
1265  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1266  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1267 
1268  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1269  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1270 
1271  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1272  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1273 
1274  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1275  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1276 
1277  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1278  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1279  {75, 4, RailGraphics->gl75}};
1280 
1281  for(int x = 0; x < 40; x++)
1282  {
1283  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1284  }
1285 
1286  TSigElement TempSigTableGroundSignal[40] =
1290 
1294 
1298 
1302 
1303  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1306 
1307  for(int x = 0; x < 40; x++)
1308  {
1309  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1310  }
1311 
1312  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1313  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1314  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1315 
1316  for(int x = 0; x < 8; x++)
1317  {
1318  FailedSigTable[x] = TempFailedSigTable[x];
1319  }
1320 
1321  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1322  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1323  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1324 
1325  for(int x = 0; x < 8; x++)
1326  {
1327  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1328  }
1329 
1330 /*
1331  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1332  a single location. These are as follows:-
1333  Directly Adjacent = up, down, left or right - NOT diagonal.
1334  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1335  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1336  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1337 
1338  //t 76
1339  //b 77
1340  //l 78
1341  //r 79
1342  //c 96
1343  //v fb 129
1344  //h fb 130
1345  //v underpass 145
1346  //h underpass 146
1347  //n 131
1348 */
1349 
1350  int Tag76[25][3] =
1351  {{-1, 0, 96}, // c top plat
1352  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1353  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1354  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1355  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1356  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1357  {0, 0, 129}, {0, -1, 145}, // v up
1358  {0, 0, 145}};
1359 
1360  for(int x = 0; x < 25; x++)
1361  {
1362  for(int y = 0; y < 3; y++)
1363  {
1364  Tag76Array[x][y] = Tag76[x][y];
1365  }
1366  }
1367 
1368  int Tag77[25][3] =
1369  {{-1, 0, 96}, // c bot plat
1370  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1371  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1372  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1373  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1374  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1375  {0, 0, 129}, {0, 1, 145}, // v up
1376  {0, 0, 145}};
1377 
1378  for(int x = 0; x < 25; x++)
1379  {
1380  for(int y = 0; y < 3; y++)
1381  {
1382  Tag77Array[x][y] = Tag77[x][y];
1383  }
1384  }
1385 
1386  int Tag78[25][3] =
1387  {{-1, 0, 96}, // c left plat
1388  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1389  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1390  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1391  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1392  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1393  {0, 0, 130}, {-1, 0, 146}, // h up
1394  {0, 0, 146}};
1395 
1396  for(int x = 0; x < 25; x++)
1397  {
1398  for(int y = 0; y < 3; y++)
1399  {
1400  Tag78Array[x][y] = Tag78[x][y];
1401  }
1402  }
1403 
1404  int Tag79[25][3] =
1405  {{-1, 0, 96}, // c right plat
1406  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1407  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1408  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1409  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1410  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1411  {0, 0, 130}, {1, 0, 146}, // h up
1412  {0, 0, 146}};
1413 
1414  for(int x = 0; x < 25; x++)
1415  {
1416  for(int y = 0; y < 3; y++)
1417  {
1418  Tag79Array[x][y] = Tag79[x][y];
1419  }
1420  }
1421 
1422  int Tag96[28][3] =
1423  {{-1, 0, 96}, // c //concourse
1424  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1425  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1426  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1427  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1428  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1429  {0, -1, 129}, {1, 0, 130}, // h fb
1430  {-1, 0, 130}, {0, 1, 145}, // v up
1431  {0, -1, 145}, {1, 0, 146}, // h up
1432  {-1, 0, 146}};
1433 
1434  for(int x = 0; x < 28; x++)
1435  {
1436  for(int y = 0; y < 3; y++)
1437  {
1438  Tag96Array[x][y] = Tag96[x][y];
1439  }
1440  }
1441 
1442  int Tag129[8][3] = // vert fb
1443  {{0, -1, 96}, // c
1444  {0, -1, 77}, // b
1445  {0, -1, 129}, // v fb
1446 
1447  {0, 1, 96}, // c
1448  {0, 1, 76}, // t
1449  {0, 1, 129}, // v fb
1450 
1451  {0, 0, 76}, // t
1452  {0, 0, 77}}; // b
1453 
1454  for(int x = 0; x < 8; x++)
1455  {
1456  for(int y = 0; y < 3; y++)
1457  {
1458  Tag129Array[x][y] = Tag129[x][y];
1459  }
1460  }
1461 
1462  int Tag145[8][3] = // vert up
1463  {{0, -1, 96}, // c
1464  {0, -1, 77}, // b
1465  {0, -1, 145}, // v fb
1466 
1467  {0, 1, 96}, // c
1468  {0, 1, 76}, // t
1469  {0, 1, 145}, // v fb
1470 
1471  {0, 0, 76}, // t
1472  {0, 0, 77}}; // b
1473 
1474  for(int x = 0; x < 8; x++)
1475  {
1476  for(int y = 0; y < 3; y++)
1477  {
1478  Tag145Array[x][y] = Tag145[x][y];
1479  }
1480  }
1481 
1482  int Tag130[8][3] = // hor fb
1483  {{-1, 0, 96}, // c
1484  {-1, 0, 79}, // r
1485  {-1, 0, 130}, // h fb
1486 
1487  {1, 0, 96}, // c
1488  {1, 0, 78}, // l
1489  {1, 0, 130}, // h fb
1490 
1491  {0, 0, 78}, // l
1492  {0, 0, 79}}; // r
1493 
1494  for(int x = 0; x < 8; x++)
1495  {
1496  for(int y = 0; y < 3; y++)
1497  {
1498  Tag130Array[x][y] = Tag130[x][y];
1499  }
1500  }
1501 
1502  int Tag146[8][3] = // hor up
1503  {{-1, 0, 96}, // c
1504  {-1, 0, 79}, // r
1505  {-1, 0, 146}, // h fb
1506 
1507  {1, 0, 96}, // c
1508  {1, 0, 78}, // l
1509  {1, 0, 146}, // h fb
1510 
1511  {0, 0, 78}, // l
1512  {0, 0, 79}}; // r
1513 
1514  for(int x = 0; x < 8; x++)
1515  {
1516  for(int y = 0; y < 3; y++)
1517  {
1518  Tag146Array[x][y] = Tag146[x][y];
1519  }
1520  }
1521 
1522  int Tag131[4][3] =
1523  {{-1, 0, 131}, // n
1524  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1525 
1526  for(int x = 0; x < 4; x++)
1527  {
1528  for(int y = 0; y < 3; y++)
1529  {
1530  Tag131Array[x][y] = Tag131[x][y];
1531  }
1532  }
1533 
1534  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1535  {
1536  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1537  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1538  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1539  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1540  140, 144, 145, 146
1541  };
1542 
1543  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1544  {
1545  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1546  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1547  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1548  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1549  141, 144, 145, 146
1550  };
1551 
1552  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1553  {
1554  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1555  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1556  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1557  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1558  141, 144, 146, 145
1559  };
1560 
1561  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1562  {
1563  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1564  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1565  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1566  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1567  140, 144, 146, 145
1568  };
1569 
1570  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1571  {
1572  FlipArray[x] = InternalFlipArray[x];
1573  MirrorArray[x] = InternalMirrorArray[x];
1574  RotRightArray[x] = InternalRotRightArray[x];
1575  RotLeftArray[x] = InternalRotLeftArray[x];
1576  }
1577 }
1578 
1579 // ---------------------------------------------------------------------------
1581 {
1582 // delete TrackVectorPtr;
1583 // delete FixedTrackArrayPtr;
1584  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1585 
1586  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1587  {
1588  delete UGMIt->second;
1589  UGMIt++;
1590  }
1591  delete GapFlashGreen;
1592  delete GapFlashRed;
1593  // all the rest are cleared by the relevant automatic destructors
1594 }
1595 
1596 // ---------------------------------------------------------------------------
1597 
1599 {
1600  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1601  {
1602 // loc 0 not used, set to bmSolidBgnd
1606 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1626  };
1627 
1628  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1629  {
1630 // loc 0 not used, set to smSolidBgnd
1634 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1653  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1654  };
1655 
1656 // track types
1657  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1658  {
1659  Erase, // 1 0
1660  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1661  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1662  Crossover, Crossover, // 2 15-16
1663  Unused, // 17 (was for text in earlier development) //1 17
1666  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1670  Platform, Platform, Platform, Platform, // 4 76-79
1673  Concourse, // 1 96
1676  Simple, Simple, Simple, Simple, // 4 125-128
1677  FootCrossing, FootCrossing, // 2 129-130
1678  NamedNonStationLocation, // 1 131
1679  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1680  Simple, Simple, Simple, Simple, // 4 140-143
1681  LevelCrossing, // 1 144
1682  FootCrossing, FootCrossing // 2 145 & 146
1683  };
1684 
1685 // links
1686  int Links[FirstUnusedSpeedTagNumber][4] =
1687  {{-1, -1, -1, -1}, // erase element
1688  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1689  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1690 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1691  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1692  {-1, -1, -1, -1}, // unused
1693  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1694  {2, 7, -1, -1}, // simple
1695  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1696 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1697 // (or right diverging if no straight)
1698  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1699  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1700  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1701  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1702  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1703  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1704  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1705  {-1, -1, -1, -1}, // Concourse
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1707  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1708  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1709  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1710  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1711  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1712  {-1, -1, -1, -1}, // NamedNonStationLocation
1713  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1714 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1715  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1716  {-1, -1, -1, -1}, // level crossing
1717  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1718  };
1719 
1721  {{NotSet, NotSet, NotSet, NotSet}, // unused
1725  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1727  {NotSet, NotSet, NotSet, NotSet}, // unused
1731  {Connection, Connection, NotSet, NotSet}, // simple
1735  {Lead, Trail, Lead, Trail}, // points
1737  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1745  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1751  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1760  {Connection, Connection, NotSet, NotSet}, // Arrows
1762  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1764  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1766  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1767  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1768  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1769  };
1770 
1771  for(int x = 0; x < 17; x++)
1772  {
1773  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1774  }
1775  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1776 // 17 was the old text value so don't want any graphics (now disused)
1777  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1778  {
1779  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1780  }
1781 }
1782 
1783 // ---------------------------------------------------------------------------
1784 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1785  ExistingGraphicLoaded(false), Width(16), Height(16)
1786 {
1787  OriginalGraphic = new Graphics::TBitmap;
1788  OriginalGraphic->PixelFormat = pf8bit;
1789  OriginalGraphic->Width = Width;
1790  OriginalGraphic->Height = Height;
1791  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1792 }
1793 
1794 // ---------------------------------------------------------------------------
1795 
1796 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1797  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1798 {
1799  OriginalGraphic = new Graphics::TBitmap;
1800  OriginalGraphic->PixelFormat = pf8bit;
1801  OriginalGraphic->Width = Width;
1802  OriginalGraphic->Height = Height;
1803  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1804 }
1805 
1806 // ---------------------------------------------------------------------------
1807 
1809 {
1810  delete OriginalGraphic;
1811 }
1812 
1813 // ---------------------------------------------------------------------------
1814 
1815 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1816 {
1817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1818  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1819  VPos = VPosIn;
1820  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1821 
1822  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1823  SourceRect.init(Left, Top, Left + Width, Top + Height);
1824  ScreenSourceSet = true;
1825  Utilities->CallLogPop(422);
1826 }
1827 
1828 // ---------------------------------------------------------------------------
1829 
1831 {
1832  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1833  if(!OverlayLoaded)
1834  {
1835  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1836  }
1837  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1838  {
1839  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1840  }
1841  if(!ScreenSourceSet)
1842  {
1843  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1844  }
1845  if(ExistingGraphicLoaded) // can only call one of the load functions
1846  {
1847  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1848  }
1849  if(OverlayPlotted) // don't load from screen if overlay plotted
1850  {
1851  Utilities->CallLogPop(775);
1852  return;
1853  }
1854  TRect DestRect(0, 0, Width, Height);
1855 
1857  OriginalLoaded = true;
1858  ScreenGraphicLoaded = true;
1859  Utilities->CallLogPop(423);
1860 }
1861 
1862 // ---------------------------------------------------------------------------
1863 
1864 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1865 /*
1866  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1867 */
1868 {
1869  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1870  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1871  if(!OverlayLoaded)
1872  {
1873  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1874  }
1875  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1876  {
1877  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1878  }
1879  if(ScreenGraphicLoaded) // can only call one of the load functions
1880  {
1881  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1882  }
1883  Width = WidthIn;
1884  Height = HeightIn;
1885  OriginalGraphic->Width = Width;
1886  OriginalGraphic->Height = Height;
1887  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1888  VPos += VOffset;
1889  TRect DestRect(0, 0, Width, Height);
1890 
1891  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1892  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1893  OriginalLoaded = true;
1894  ExistingGraphicLoaded = true;
1895  Utilities->CallLogPop(424);
1896 }
1897 
1898 // ---------------------------------------------------------------------------
1899 
1900 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1901 {
1902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1903  OverlayGraphic = Overlay;
1904  OverlayLoaded = true;
1905  Utilities->CallLogPop(425);
1906 }
1907 
1908 // ---------------------------------------------------------------------------
1909 
1911 {
1912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1913  if(!OverlayLoaded)
1914  {
1915  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1916  }
1917  if(!OverlayPlotted)
1918  {
1919  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1920  Disp->Update();
1921  OverlayPlotted = true;
1922  }
1923  Utilities->CallLogPop(426);
1924 }
1925 
1926 // ---------------------------------------------------------------------------
1927 
1929 {
1930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1931  if(OverlayPlotted)
1932  {
1933  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1934  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1935  {
1936  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1937  }
1938  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1939  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1940  OverlayPlotted = false;
1941  }
1942  Utilities->CallLogPop(427);
1943 }
1944 
1945 // ---------------------------------------------------------------------------
1946 
1948 {
1949  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1950  bool TrackPresent = false;
1951 
1952  if(InactiveTrackVector.size() != 0)
1953  {
1954  Utilities->CallLogPop(1333);
1955  return(false);
1956  }
1957  else if(TrackVector.size() == 0)
1958  {
1959  Utilities->CallLogPop(1334);
1960  return(true);
1961  }
1962  else
1963  {
1964  for(unsigned int x = 0; x < TrackVector.size(); x++)
1965  {
1966  if((TrackElementAt(1042, x).SpeedTag != 0))
1967  {
1968  TrackPresent = true;
1969  }
1970  }
1971  }
1972  Utilities->CallLogPop(1335);
1973  return(!TrackPresent);
1974 }
1975 
1976 // ---------------------------------------------------------------------------
1977 
1978 bool TTrack::NoActiveTrack(int Caller)
1979 {
1980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1981  bool TrackPresent = false;
1982 
1983  if(TrackVector.size() == 0)
1984  {
1985  Utilities->CallLogPop(1582);
1986  return(true);
1987  }
1988  else
1989  {
1990  for(unsigned int x = 0; x < TrackVector.size(); x++)
1991  {
1992  if((TrackElementAt(1043, x).SpeedTag != 0))
1993  {
1994  TrackPresent = true;
1995  }
1996  break;
1997  }
1998  }
1999  Utilities->CallLogPop(1583);
2000  return(!TrackPresent);
2001 }
2002 
2003 // ---------------------------------------------------------------------------
2004 
2005 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2006 {
2007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2008  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2009  TrackEraseSuccessfulFlag = false;
2010 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
2011 // since have to match platforms as well as track
2012 // used to set TrackFinished to false if an element erased
2013 
2014  ErasedTrackVectorPosition = -1; // marker for no element erased
2015  AnsiString SName = "", ErrorString;
2017  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2018  TTrackMapIterator TrackMapPtr;
2019  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2020 
2021  if(TrackVector.size() != 0)
2022  {
2023  TrackMapKeyPair.first = HLocInput;
2024  TrackMapKeyPair.second = VLocInput;
2025  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2026  if(TrackMapPtr != TrackMap.end())
2027  {
2028  bool FoundFlag;
2029  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2030  if(FoundFlag) // should find it as it's in the map
2031  {
2032  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2033  {
2034  SName = TrackElementAt(1, VecPos).LocationName;
2035  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2036  if(ErrorString != "")
2037  {
2038  throw Exception(ErrorString + " for EraseTrackElement 1");
2039  }
2040  LocationNameMultiMap.erase(SNIt);
2041  }
2042  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2043  // ensure erase vector element before map element as iterator no longer valid after a map erase
2044  TrackMap.erase(TrackMapPtr);
2045  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2046  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2048  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2049  if(SName != "")
2050  {
2051  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2052  int HPos, VPos;
2053  if(TextHandler->FindText(1, SName, HPos, VPos))
2054  {
2055  if(TextHandler->TextErase(5, HPos, VPos, SName))
2056  {
2057  ;
2058  } // condition not used
2059 
2060  }
2061  }
2062  ErasedTrackVectorPosition = VecPos;
2063  TrackEraseSuccessfulFlag = true;
2064  }
2065  }
2066  }
2067  if(InactiveTrackVector.size() != 0)
2068  {
2069  unsigned int VecPos;
2070  InactiveTrackMapKeyPair.first = HLocInput;
2071  InactiveTrackMapKeyPair.second = VLocInput;
2072  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2073  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2074  {
2075  SName = "";
2076  VecPos = InactiveTrack2MultiMapIterator->second;
2077  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2078  {
2079  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2080  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2081  if(ErrorString != "")
2082  {
2083  throw Exception(ErrorString + " for EraseTrackElement 2A");
2084  }
2085  LocationNameMultiMap.erase(SNIt);
2086  }
2087  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2088  // ensure erase vector element before map element as iterator no longer valid after a map erase
2089  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2090  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2091  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2093  TrackEraseSuccessfulFlag = true;
2094  if(SName != "")
2095  {
2096  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2097  int HPos, VPos;
2098  if(TextHandler->FindText(2, SName, HPos, VPos))
2099  {
2100  if(TextHandler->TextErase(6, HPos, VPos, SName))
2101  {
2102  ;
2103  } // condition not used
2104 
2105  }
2106  }
2107  }
2108  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2109  {
2110  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2111  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2112  {
2113  SName = "";
2114  VecPos = InactiveTrack2MultiMapIterator->second;
2115  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2116  {
2117  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2118  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2119  if(ErrorString != "")
2120  {
2121  throw Exception(ErrorString + " for EraseTrackElement 2B");
2122  }
2123  LocationNameMultiMap.erase(SNIt);
2124  }
2125  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2126  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2127  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2129  if(SName != "")
2130  {
2131  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2132  int HPos, VPos;
2133  if(TextHandler->FindText(3, SName, HPos, VPos))
2134  {
2135  if(TextHandler->TextErase(7, HPos, VPos, SName))
2136  {
2137  ;
2138  } // condition not used
2139 
2140  }
2141  }
2142  }
2143  }
2144  }
2145  if(TrackEraseSuccessfulFlag)
2146  {
2147  CalcHLocMinEtc(2);
2148  SetTrackFinished(false);
2149  }
2150  if(InternalChecks)
2151  {
2152  CheckMapAndTrack(1); // test
2153  CheckMapAndInactiveTrack(1); // test
2154  CheckLocationNameMultiMap(6); // test
2155  }
2156  Utilities->CallLogPop(428);
2157 }
2158 
2159 // ---------------------------------------------------------------------------
2160 
2161 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks, bool PerformNameSearch)
2162 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2163 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2164 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2165 // PerformNameSearch added at v2.18.0 to speed up named element additions when area selected
2166 {
2167  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2168  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2169  bool PlatAllowedFlag = false;
2170 
2171  TrackLinkingRequiredFlag = false;
2172 /*
2173  Not erase, that covered separately.
2174  First check if Current SpeedButton assigned, then check if a platform and only
2175  permit if an appropriate trackpiece already there & not a same platform there.
2176  - can't enter a platform without track first.
2177  Then for non-platforms, check if a track piece already present at location &
2178  reject if so.
2179 */
2180 
2181  TLocationNameMultiMapEntry LocationNameEntry;
2182 
2183  LocationNameEntry.first = "";
2184  if(CurrentTag == 0)
2185  {
2186  Utilities->CallLogPop(429);
2187  return; // not assigned yet
2188  }
2189  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2190 
2191  TempTrackElement.HLoc = HLocInput;
2192  TempTrackElement.VLoc = VLocInput;
2193  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2194 // new at version 0.6 - set signal aspect depending on build mode
2195 
2196  if(TempTrackElement.TrackType == SignalPost)
2197  {
2198  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2199  // pasting a SignalPost can only have values 1 to 4
2200  {
2202  {
2203  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2204  }
2206  {
2207  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2208  }
2210  {
2211  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2212  }
2213  else
2214  {
2215  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2216  }
2217  }
2218  else if(Aspect == 1)
2219  {
2220  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2221  }
2222  else if(Aspect == 2)
2223  {
2224  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2225  }
2226  else if(Aspect == 3)
2227  {
2228  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2229  }
2230  else
2231  {
2232  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2233  }
2234  }
2235  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2236  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2237  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2238  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2239 
2240  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2241  {
2243  {
2244  NonStationOrLevelCrossingPresent = true;
2245  }
2246  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2247  {
2248  NonStationOrLevelCrossingPresent = true;
2249  }
2250  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2251  {
2252  PlatformPresent = true;
2253  }
2254  // no need to check IMPair.second since if that exists it is because .first is a platform
2255  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2256  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2257  }
2258 // check platforms
2259  if(TempTrackElement.TrackType == Platform)
2260  {
2261  if(FoundFlag) // active track element already there
2262  {
2263  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2264  {
2265  ;
2266  }
2267  // same platform type already there so above keeps PlatAllowedFlag false
2268  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2269  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2270  {
2271  PlatAllowedFlag = true;
2272  }
2273  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2274  {
2275  PlatAllowedFlag = true;
2276  }
2277  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2278  {
2279  PlatAllowedFlag = true;
2280  }
2281  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2282  {
2283  PlatAllowedFlag = true;
2284  }
2285  if(PlatAllowedFlag)
2286  {
2287  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2288  TrackPush(1, TempTrackElement);
2289  if(PerformNameSearch)
2290  {
2291  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2292  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2293  // Must be called AFTER TrackPush
2294  // No need to plot the element - Clearand ... called after this function called
2295  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2296  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2297  }
2298 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2299 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2300 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2301  if(InternalChecks)
2302  {
2303  CheckMapAndInactiveTrack(5); // test
2304  CheckLocationNameMultiMap(4); // test
2305  }
2306  Utilities->CallLogPop(430);
2307  return;
2308  }
2309  } // if(FoundFlag)
2310 
2311  Utilities->CallLogPop(431);
2312  return;
2313  } // if platform
2314 
2315 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2316  if(TempTrackElement.TrackType == NamedNonStationLocation)
2317  {
2318  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2319  (!FoundFlag && !InactiveFoundFlag))
2320  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2321  {
2322  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2323  TrackPush(2, TempTrackElement);
2324  if(PerformNameSearch)
2325  {
2326  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2327  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2328  }
2329  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2330  {
2331 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2332 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2333 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2334  }
2335  if(InternalChecks)
2336  {
2337  CheckMapAndInactiveTrack(11); // test
2338  CheckLocationNameMultiMap(12); // test
2339  }
2340  Utilities->CallLogPop(432);
2341  return;
2342  }
2343  else
2344  {
2345  Utilities->CallLogPop(433);
2346  return;
2347  }
2348  }
2349 // check if a level crossing - OK if placed on a plain straight track
2350  if(TempTrackElement.TrackType == LevelCrossing)
2351  {
2352  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2353  {
2354  TrackPush(11, TempTrackElement);
2355  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2356 // no need for reference to LC element as can't be open
2357  TrackLinkingRequiredFlag = true;
2358  Utilities->CallLogPop(1907);
2359  return;
2360  }
2361  else
2362  {
2363  Utilities->CallLogPop(1906);
2364  return; // was a level crossing but can't place it for some reason
2365  }
2366  }
2367 
2368 // check if another element already there
2369  else if(FoundFlag || InactiveFoundFlag)
2370  {
2371  Utilities->CallLogPop(434);
2372  return; // something already there (active or inactive track)
2373  }
2374 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2375 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2376 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2377 // do this after pushed into vector so that can use EnterLocationName
2378 
2379  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2380  {
2381  TrackPush(3, TempTrackElement);
2382  if(PerformNameSearch)
2383  {
2384  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2385  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2386  }
2387  }
2388  else if(TempTrackElement.TrackType == Points)
2389  {
2390  TrackPush(4, TempTrackElement);
2391  bool BothPointFillets = true;
2392  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2393  }
2394  else if(TempTrackElement.TrackType == SignalPost)
2395  {
2396  TrackPush(10, TempTrackElement);
2397  PlotSignal(12, TempTrackElement, Display);
2398  }
2399  else
2400  {
2401  TrackPush(5, TempTrackElement);
2402  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2403  }
2404  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2405  {
2406  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2407  }
2408  if(InternalChecks && PerformNameSearch) //don't carry out checks if PerformNameSearch false else will fail, should be set correctly in calling function but include to be sure
2409  {
2410  CheckMapAndTrack(2); // test
2411  CheckMapAndInactiveTrack(2); // test
2412  CheckLocationNameMultiMap(5); // test
2413  }
2414  Utilities->CallLogPop(2062);
2415 }
2416 
2417 // ---------------------------------------------------------------------------
2418 
2419 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2420  bool InternalChecks)
2421 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2422 {
2423  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2424  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2425  bool PlatAllowedFlag = false;
2426 
2427  TrackLinkingRequiredFlag = false;
2428  TLocationNameMultiMapEntry LocationNameEntry;
2429 
2430  LocationNameEntry.first = "";
2431  if(TempTrackElement.SpeedTag == 0)
2432  {
2433  Utilities->CallLogPop(2063);
2434  return; // not assigned yet
2435  }
2436  TempTrackElement.HLoc = HLocInput;
2437  TempTrackElement.VLoc = VLocInput;
2438  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2439  for(int x = 0; x < 4; x++) // unset any gaps,
2440  {
2441  if(TempTrackElement.Config[x] == Gap)
2442  {
2443  TempTrackElement.ConnLinkPos[x] = -1;
2444  }
2445  TempTrackElement.Conn[x] = -1;
2446  }
2447  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2448 // new at version 0.6 - set signal aspect depending on build mode
2449  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2450 
2451  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2452  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2453  // for the active track element because these aren't set
2454  // if don't do this then get a mismatch error during map checks later
2455 
2456  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2457 
2458  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2459  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2460 
2461  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2462  {
2463  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2464  {
2465  NonStationOrLevelCrossingPresent = true;
2466  }
2467  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2468  {
2469  NonStationOrLevelCrossingPresent = true;
2470  }
2471  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2472  {
2473  PlatformPresent = true;
2474  }
2475  // no need to check IMPair.second since if that exists it is because .first is a platform
2476  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2477  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2478  }
2479 // check platforms
2480  if(TempTrackElement.TrackType == Platform)
2481  {
2482  if(FoundFlag) // active track element already there
2483  {
2484  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2485  {
2486  ;
2487  }
2488  // same platform type already there so above keeps PlatAllowedFlag false
2489  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2490  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2491  {
2492  PlatAllowedFlag = true;
2493  }
2494  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2495  {
2496  PlatAllowedFlag = true;
2497  }
2498  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2499  {
2500  PlatAllowedFlag = true;
2501  }
2502  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2503  {
2504  PlatAllowedFlag = true;
2505  }
2506  if(PlatAllowedFlag)
2507  {
2508  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2509  TrackPush(12, TempTrackElement);
2510 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2511  {
2512  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2513  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2514  }
2515  // Must be called AFTER TrackPush
2516 // No need to plot the element - Clearand ... called after this function called
2517  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2518  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2519 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2520 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2521 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2522  if(InternalChecks)
2523  {
2524  CheckMapAndInactiveTrack(12); // test
2525  CheckLocationNameMultiMap(20); // test
2526  }
2527  Utilities->CallLogPop(2064);
2528  return;
2529  }
2530  } // if(FoundFlag)
2531 
2532  Utilities->CallLogPop(2065);
2533  return;
2534  } // if platform
2535 
2536 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2537  if(TempTrackElement.TrackType == NamedNonStationLocation)
2538  {
2539  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2540  (!FoundFlag && !InactiveFoundFlag))
2541  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2542  {
2543  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2544  TrackPush(13, TempTrackElement);
2545 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2546  {
2547  {
2548  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2549  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2550  }
2551  }
2552  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2553  {
2554 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2555 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2556 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2557  }
2558  if(InternalChecks)
2559  {
2560  CheckMapAndInactiveTrack(13); // test
2561  CheckLocationNameMultiMap(21); // test
2562  }
2563  Utilities->CallLogPop(2066);
2564  return;
2565  }
2566  else
2567  {
2568  Utilities->CallLogPop(2067);
2569  return;
2570  }
2571  }
2572 // check if a level crossing - OK if placed on a plain straight track
2573  if(TempTrackElement.TrackType == LevelCrossing)
2574  {
2575  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2576  {
2577  TrackPush(14, TempTrackElement);
2578  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2579 // no need for reference to LC element as can't be open
2580  TrackLinkingRequiredFlag = true;
2581  Utilities->CallLogPop(2068);
2582  return;
2583  }
2584  else
2585  {
2586  Utilities->CallLogPop(2069);
2587  return; // was a level crossing but can't place it for some reason
2588  }
2589  }
2590 
2591 // check if another element already there
2592  else if(FoundFlag || InactiveFoundFlag)
2593  {
2594  Utilities->CallLogPop(2070);
2595  return; // something already there (active or inactive track)
2596  }
2597 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2598 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2599 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2600 // do this after pushed into vector so that can use EnterLocationName
2601 
2602  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2603  {
2604  TrackPush(15, TempTrackElement);
2605  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2606  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2607  }
2608  else if(TempTrackElement.TrackType == Points)
2609  {
2610  TrackPush(16, TempTrackElement);
2611  bool BothPointFillets = true;
2612  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2613  }
2614  else if(TempTrackElement.TrackType == SignalPost)
2615  {
2616  TrackPush(17, TempTrackElement);
2617  PlotSignal(14, TempTrackElement, Display);
2618  }
2619  else
2620  {
2621  TrackPush(18, TempTrackElement);
2622  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2623  }
2624  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2625  {
2626  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2627  }
2628  if(InternalChecks)
2629  {
2630  CheckMapAndTrack(12); // test
2631  CheckMapAndInactiveTrack(14); // test
2632  CheckLocationNameMultiMap(22); // test
2633  }
2634  Utilities->CallLogPop(2071);
2635 }
2636 
2637 // ---------------------------------------------------------------------------
2638 
2639 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2640 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2641 // return bool = true for success
2642 // LocError = true for location error & HLoc & VLoc to be inverted
2643 {
2644  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2645  LocError = false;
2646  SetTrackFinished(false);
2647  if(TrackVector.size() == 0)
2648  {
2649  Utilities->CallLogPop(437);
2650  return(false);
2651  }
2652  if(GapsUnset(7))
2653  {
2654  if(GiveMessages)
2655  {
2656  ShowMessage("Gaps must be set before track can be validated");
2657  }
2658  Utilities->CallLogPop(1135);
2659  return(false);
2660  }
2661 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2662 // returns true for any unset gaps
2664  {
2665  // can keep this exception as protected by the GapsUnset call above
2666  throw Exception("Error, gaps unset when TryToConnectTrack called");
2667  }
2669  CheckGapMap(1); // test
2670 // Gap connections now securely defined
2671 
2672  CheckMapAndTrack(8); // test
2673 
2674 // Perform a pre-check prior to TrackMap being compiled
2675  if(GiveMessages)
2676  {
2677  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2678  {
2679  Utilities->CallLogPop(439);
2680  return(false);
2681  }
2682  }
2683  else
2684  {
2685  if(!LinkTrackNoMessages(1, false))
2686  {
2687  Utilities->CallLogPop(1131);
2688  return(false);
2689  }
2690  }
2691 // here if pre-check successful
2692  if(!RepositionAndMapTrack(0))
2693  {
2694  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2695  Utilities->CallLogPop(1138);
2696  return(false);
2697  }
2698 // now perform the final assembly - FinalCall = true
2699  if(GiveMessages)
2700  {
2701  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2702  {
2703  Utilities->CallLogPop(1116);
2704  return(false);
2705  }
2706  }
2707  else
2708  {
2709  if(!LinkTrackNoMessages(2, true))
2710  {
2711  Utilities->CallLogPop(1132);
2712  return(false);
2713  }
2714  }
2715 // success
2716 
2717  PopulateLCVector(0);
2718  CheckGapMap(2); // test
2719  CheckMapAndTrack(3); // test
2720  CheckMapAndInactiveTrack(3); // test
2721  CheckLocationNameMultiMap(9); // test
2722  SetTrackFinished(true);
2723 
2724 // Build ContinuationNameMap
2725  std::pair<AnsiString, char>TempMapPair;
2726 
2727  ContinuationNameMap.clear();
2728  for(int x = 0; x < Track->TrackVectorSize(); x++)
2729  {
2730  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2731  {
2732  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2733  TempMapPair.second = 'x'; // unused
2734  ContinuationNameMap.insert(TempMapPair);
2735  }
2736  }
2737 
2738 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2739 //(don't report blue areas without track as these unlikely to be mistakes)
2740 
2741  if(TrackFinished)
2742  {
2743  AnsiString Name = "";
2744  typedef std::list<AnsiString> TNoPlatsList;
2745  TNoPlatsList::iterator NPLIt;
2746  TNoPlatsList NoPlatsList;
2747  typedef std::list<AnsiString> TLocNameList;
2748  TLocNameList LocNameList; //single entry for each name
2751  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2752  {
2753  LocNameList.push_back(LNMMIt->first);
2754  }
2755  LocNameList.sort();
2756  LocNameList.unique();
2757  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2758  {
2759  Name = *LNLIt;
2760  MMRange = LocationNameMultiMap.equal_range(Name);
2761  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2762  {
2763  continue;
2764  }
2765  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2766  {
2767  if((LNMMIt->second) < 0) //active track element
2768  {
2769  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2770  {
2771  break;
2772  }
2773  }
2774  else //inactive
2775  {
2776  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2777  {
2778  break;
2779  }
2780  }
2781  TempIt = MMRange.second;
2782  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2783  {
2784  NoPlatsList.push_back(Name);
2785  }
2786  }
2787  }
2788  if(!NoPlatsList.empty())
2789  {
2790  AnsiString NoPlatsAnsiList = "";
2791  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2792  {
2793  NoPlatsAnsiList += *NPLIt + '\n';
2794  }
2796  {
2797  if(NoPlatsList.size() > 1)
2798  {
2799  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2800  }
2801  else
2802  {
2803  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2804  }
2805  Utilities->NoPlatsMessageSent = true;
2806  }
2807  }
2808  }
2809  Utilities->CallLogPop(440);
2810  return(true);
2811 }
2812 
2813 // ---------------------------------------------------------------------------
2814 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2815 // unused - too time-consuming - double brute force search
2816 {
2817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2818  int NewHLoc, NewVLoc;
2819  bool ConnectionFoundFlag, LinkFoundFlag;
2820 
2821  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2822  {
2823  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2824  {
2825  if(TrackElementAt(1061, x).Link[y] <= 0)
2826  {
2827  continue; // no link
2828  }
2829  if(TrackElementAt(1062, x).Config[y] == End)
2830  {
2831  continue; // buffer or continuation
2832  }
2833  if(TrackElementAt(1063, x).Config[y] == Gap)
2834  {
2835  continue; // gap jump
2836  }
2837  // get required H & V for track element joining link 'y'
2838  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2839  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2840  // find track element if present
2841  ConnectionFoundFlag = false;
2842  for(unsigned int z = 0; z < TrackVector.size(); z++)
2843  {
2844 // if(TrackElementAt(5, z).TrackType == Platform)
2845 // continue; //skip platforms
2846  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2847  {
2848  ConnectionFoundFlag = true;
2849  // find connecting link in the newly found track element if there is one
2850  LinkFoundFlag = false;
2851  for(unsigned int a = 0; a < 4; a++)
2852  {
2853  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2854  {
2855  LinkFoundFlag = true;
2856  }
2857  }
2858  // if there isn't a corresponding link set the invert values for the offending element
2859  if(!LinkFoundFlag)
2860  {
2861  HLoc = TrackElementAt(1072, x).HLoc;
2862  VLoc = TrackElementAt(1073, x).VLoc;
2863  Utilities->CallLogPop(441);
2864  return(true);
2865  }
2866  break; // success, so break out of 'z' loop
2867  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2868 
2869  } // for z...
2870  // if there isn't a connection set the invert values for the offending element
2871  if(!ConnectionFoundFlag)
2872  {
2873  HLoc = TrackElementAt(1074, x).HLoc;
2874  VLoc = TrackElementAt(1075, x).VLoc;
2875  Utilities->CallLogPop(442);
2876  return(true);
2877  }
2878  } // for y....
2879  } // for x...
2880  Utilities->CallLogPop(443);
2881  return(false); // all OK
2882 }
2883 
2884 // ---------------------------------------------------------------------------
2885 
2886 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2887 {
2888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2889  TrackElement.LogTrack(0));
2890  bool FoundFlag;
2891 
2892  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2893  if(FoundFlag)
2894  {
2895  TrackElement = TrackElementAt(1076, Position);
2896  }
2897  Utilities->CallLogPop(444);
2898  return(FoundFlag);
2899 }
2900 
2901 // ---------------------------------------------------------------------------
2902 
2904 {
2905  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2906  if(NextTrackElementPtr >= TrackVector.end())
2907  {
2908  Utilities->CallLogPop(1336);
2909  return(false);
2910  }
2911  Next = *NextTrackElementPtr;
2913  Utilities->CallLogPop(1337);
2914  return(true);
2915 }
2916 
2917 // ---------------------------------------------------------------------------
2918 
2920 {
2921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2923  {
2924  Utilities->CallLogPop(1338);
2925  return(false);
2926  }
2927  Next = *NextTrackElementPtr;
2929  Utilities->CallLogPop(1339);
2930  return(true);
2931 }
2932 
2933 // ---------------------------------------------------------------------------
2934 
2935 int TTrack::NumberOfGaps(int Caller)
2936 
2937 {
2938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2939  int Count = 0;
2940 
2941  if(TrackVector.size() == 0)
2942  {
2943  Utilities->CallLogPop(1340);
2944  return(0);
2945  }
2946  for(unsigned int x = 0; x < TrackVector.size(); x++)
2947  {
2948  if(TrackElementAt(1077, x).TrackType == GapJump)
2949  {
2950  Count++;
2951  }
2952  }
2953  Utilities->CallLogPop(1341);
2954  return(Count);
2955 }
2956 
2957 // ---------------------------------------------------------------------------
2959 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2960 // returns true for any unset gaps
2961 {
2962  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2963  bool UnsetGaps = false;
2964 
2965  if(TrackVector.size() == 0)
2966  {
2967  Utilities->CallLogPop(445);
2968  return(false);
2969  }
2970  for(unsigned int x = 0; x < TrackVector.size(); x++)
2971  {
2972  if(TrackElementAt(1078, x).TrackType != GapJump)
2973  {
2974  for(unsigned int y = 0; y < 4; y++)
2975  {
2976  TrackElementAt(1079, x).Conn[y] = -1;
2977  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2978  }
2979  }
2980  else // GapJump
2981  {
2982 // int tempint = TrackElementAt(, x).Conn[0);
2983 
2984  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2985  {
2986  for(unsigned int y = 0; y < 4; y++)
2987  {
2988  TrackElementAt(1082, x).Conn[y] = -1;
2989  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2990  }
2991  UnsetGaps = true;
2992  continue; // to next 'x'
2993  }
2994  else // set, but may not have matching element, or that element may not be set
2995  {
2996  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2997  {
2998  TrackElementAt(1084, x).Conn[y] = -1;
2999  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
3000  }
3001 
3002  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
3003  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
3004  {
3005  for(unsigned int y = 0; y < 4; y++)
3006  {
3007  TrackElementAt(1087, x).Conn[y] = -1;
3008  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
3009  }
3010  UnsetGaps = true;
3011  continue; // to next 'x'
3012  }
3013 // here if gap connection is itself a GapJump
3014  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3015  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3016  // if not clear Conns & CLks & reset Lk[0]
3017  {
3018  for(unsigned int y = 0; y < 4; y++)
3019  {
3020  TrackElementAt(1090, x).Conn[y] = -1;
3021  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3022  }
3023  UnsetGaps = true;
3024  continue; // to next 'x'
3025  }
3026 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3027 // hence no more action needed on these Conns & CLks
3028  }
3029  } // else //gap jump
3030 
3031  } // for x...
3032  Utilities->CallLogPop(446);
3033  return(UnsetGaps);
3034 }
3035 
3036 // ---------------------------------------------------------------------------
3037 
3038 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3039 {
3040 // VecFile already open and its pointer at right place on calling
3041  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3042  int TempInt;
3043 
3044  TrackClear(1);
3045 // load track elements
3046  int NumberOfActiveElements = 0;
3047 
3048  GraphicsFollow = false;
3049  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3050  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3051 
3052  if(MarkerString[MarkerString.Length()] == '1')
3053  {
3054  GraphicsFollow = true;
3055  }
3056  for(int x = 0; x < NumberOfActiveElements; x++)
3057  {
3058  VecFile >> TempInt; // TrackVectorNumber, not used
3059  VecFile >> TempInt; // SpeedTag
3060  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3061  VecFile >> TempInt;
3062  TrackElement.HLoc = TempInt;
3063  VecFile >> TempInt;
3064  TrackElement.VLoc = TempInt;
3065  if(TrackElement.TrackType == GapJump)
3066  {
3067  VecFile >> TempInt;
3068  TrackElement.ConnLinkPos[0] = TempInt;
3069  VecFile >> TempInt;
3070  TrackElement.Conn[0] = TempInt;
3071  }
3072  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3073  {
3074  VecFile >> TempInt;
3075  TrackElement.Attribute = TempInt;
3076  }
3077  if(TrackElement.TrackType == SignalPost)
3078  {
3079  VecFile >> TempInt;
3080  if(TempInt == 0)
3081  {
3082  TrackElement.CallingOnSet = false;
3083  }
3084  else
3085  {
3086  TrackElement.CallingOnSet = true;
3087  }
3088  }
3089  VecFile >> TempInt;
3090  TrackElement.Length01 = TempInt;
3091  VecFile >> TempInt;
3092  TrackElement.Length23 = TempInt;
3093  VecFile >> TempInt;
3094  if((TempInt != -1) && (TempInt < 10))
3095  {
3096  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3097  }
3098  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3099  {
3100  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3101  }
3102  TrackElement.SpeedLimit01 = TempInt;
3103  VecFile >> TempInt;
3104  if((TempInt != -1) && (TempInt < 10))
3105  {
3106  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3107  }
3108  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3109  {
3110  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3111  }
3112  TrackElement.SpeedLimit23 = TempInt;
3113 
3114  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3115  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3116  SetElementID(0, TrackElement);
3117  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3118 // new for v0.6
3119  if(TrackElement.TrackType == SignalPost)
3120  {
3121  if(Marker[1] == '3')
3122  {
3123  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3124  }
3125  else if(Marker[1] == '2')
3126  {
3127  TrackElement.SigAspect = TTrackElement::TwoAspect;
3128  }
3129  else if(Marker[1] == 'G')
3130  {
3131  TrackElement.SigAspect = TTrackElement::GroundSignal;
3132  }
3133  else
3134  {
3135  TrackElement.SigAspect = TTrackElement::FourAspect;
3136  }
3137  }
3138  if(TrackElement.SpeedTag != 0)
3139  {
3140  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3141  }
3142  }
3143  int NumberOfInactiveElements = 0;
3144 
3145  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3146  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3147  for(int x = 0; x < NumberOfInactiveElements; x++)
3148  {
3149  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3150  VecFile >> TempInt; // SpeedTag
3151  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3152  VecFile >> TempInt;
3153  TrackElement.HLoc = TempInt;
3154  VecFile >> TempInt;
3155  TrackElement.VLoc = TempInt;
3156  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3157  SetElementID(3, TrackElement);
3158  TrackPush(9, TrackElement);
3159  Utilities->LoadFileString(VecFile); // marker
3160  }
3161  bool LocError = false; // needed for TryToConnectTrack but not used
3162  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3163 
3164  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3165  {
3166  SetTrackFinished(true);
3167  }
3168  else
3169  {
3170  SetTrackFinished(false);
3171  }
3172 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3173 // CheckMapAndInactiveTrack(8);
3174 // CheckLocationNameMultiMap(10);
3175  Utilities->CallLogPop(448);
3176 }
3177 
3178 // ---------------------------------------------------------------------------
3179 
3180 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3181 {
3182 // VecFile already open and its pointer at right place on calling
3183  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3184 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3185 // & load into UserGraphicItem then store in UserGraphicVector
3186  UserGraphicVector.clear();
3187  TUserGraphicItem UGI;
3188  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3189 
3190  for(int x = 0; x < NumberOfGraphics; x++)
3191  {
3192  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3193  UGI.HPos = Utilities->LoadFileInt(VecFile);
3194  UGI.VPos = Utilities->LoadFileInt(VecFile);
3195  UGI.Width = 0; // provisional value
3196  UGI.Height = 0; // provisional value
3197  UGI.UserGraphic = NULL; // provisional value
3198  UserGraphicVector.push_back(UGI);
3199  }
3200 // now load the map & set Width, Height & TPicture*
3201  bool FileError = false;
3202 
3203  for(int x = 0; x < NumberOfGraphics; x++)
3204  {
3205  if(FileError)
3206  {
3207  break; // otherwise keeps going round the loop
3208  }
3209  UGI = UserGraphicVectorAt(0, x);
3210  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3211  {
3212  try
3213  {
3214 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3215  UGME.first = UGI.FileName;
3216  UGME.second = new TPicture;
3217  UGME.second->LoadFromFile(UGME.first); // errors caught below
3218  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3219  {
3220  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3221  }
3222  UGI.UserGraphic = UGME.second;
3223  UGI.Width = UGI.UserGraphic->Width;
3224  UGI.Height = UGI.UserGraphic->Height;
3225  UserGraphicVectorAt(1, x) = UGI;
3226  }
3227  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3228  {
3229  //message already sent in CheckUserGraphics
3230  FileError = true;
3231  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3232  if(!UserGraphicMap.empty())
3233  {
3234  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3235  {
3236  delete UGMIt->second;
3237  }
3238  UserGraphicMap.clear();
3239  }
3240  }
3241  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3242  {
3243  //message already sent in CheckUserGraphics
3244  FileError = true;
3245  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3246  if(!UserGraphicMap.empty())
3247  {
3248  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3249  {
3250  delete UGMIt->second;
3251  }
3252  UserGraphicMap.clear();
3253  }
3254  }
3255  }
3256  else
3257  {
3258  bool FoundInMap = false;
3259  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3260  {
3261  if(UGI.FileName == UGMIt->first) // already exists in map
3262  {
3263  UGI.UserGraphic = UGMIt->second;
3264  UGI.Width = UGI.UserGraphic->Width;
3265  UGI.Height = UGI.UserGraphic->Height;
3266  UserGraphicVectorAt(2, x) = UGI;
3267  FoundInMap = true;
3268  break;
3269  }
3270  }
3271  if(!FoundInMap)
3272  {
3273  try
3274  {
3276  UGME.first = UGI.FileName;
3277  UGME.second = new TPicture;
3278  UGME.second->LoadFromFile(UGME.first); // errors caught below
3279  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3280  {
3281  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3282  }
3283  UGI.UserGraphic = UGME.second;
3284  UGI.Width = UGI.UserGraphic->Width;
3285  UGI.Height = UGI.UserGraphic->Height;
3286  UserGraphicVectorAt(3, x) = UGI;
3287  }
3288  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3289  {
3290  //message already sent in CheckUserGraphics
3291  FileError = true;
3292  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3293  if(!UserGraphicMap.empty())
3294  {
3295  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3296  {
3297  delete UGMIt->second;
3298  }
3299  UserGraphicMap.clear();
3300  }
3301  }
3302  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3303  {
3304  //message already sent in CheckUserGraphics
3305  FileError = true;
3306  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3307  if(!UserGraphicMap.empty())
3308  {
3309  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3310  {
3311  delete UGMIt->second;
3312  }
3313  UserGraphicMap.clear();
3314  }
3315  }
3316  }
3317  }
3318  }
3319  Utilities->CallLogPop(2167);
3320 }
3321 
3322 // ---------------------------------------------------------------------------
3323 
3324 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3325 {
3326 // VecFile already open and its pointer at right place on calling
3327 // if GraphicsFollow true, then save Marker as **Active elements**1
3328 // save trackfinished flag
3329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3330  TTrackElement TrackElement, InactiveTrackElement;
3331 
3332 // save track elements
3333  Utilities->SaveFileInt(VecFile, TrackVector.size());
3334  if(GraphicsFollow)
3335  {
3336  VecFile << "**Active elements**1" << '\0' << '\n';
3337  }
3338  else
3339  {
3340  VecFile << "**Active elements**" << '\0' << '\n';
3341  }
3342  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3343  {
3344  TrackElement = TrackElementAt(1092, x);
3345  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3346  VecFile << TrackElement.SpeedTag << '\n';
3347  VecFile << TrackElement.HLoc << '\n';
3348  VecFile << TrackElement.VLoc << '\n';
3349  if(TrackElement.TrackType == GapJump)
3350  {
3351  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3352  VecFile << TrackElement.Conn[0] << '\n';
3353  }
3354  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3355  {
3356  VecFile << TrackElement.Attribute << '\n';
3357  }
3358  if(TrackElement.TrackType == SignalPost)
3359  {
3360  if(TrackElement.CallingOnSet)
3361  {
3362  VecFile << int(1) << '\n';
3363  }
3364  else
3365  {
3366  VecFile << int(0) << '\n';
3367  }
3368  }
3369  VecFile << TrackElement.Length01 << '\n';
3370  VecFile << TrackElement.Length23 << '\n';
3371  VecFile << TrackElement.SpeedLimit01 << '\n';
3372  VecFile << TrackElement.SpeedLimit23 << '\n';
3373  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3374  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3375 // new for v0.6
3376  if(TrackElement.TrackType == SignalPost)
3377  {
3378  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3379  {
3380  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3381  }
3382  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3383  {
3384  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3385  }
3386  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3387  {
3388  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3389  }
3390  else // 4 aspect
3391  {
3392  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3393  }
3394  }
3395  else
3396  {
3397  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3398  }
3399  }
3400 
3401  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3402  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3403  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3404  {
3405  InactiveTrackElement = InactiveTrackElementAt(136, x);
3406  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3407  VecFile << InactiveTrackElement.SpeedTag << '\n';
3408  VecFile << InactiveTrackElement.HLoc << '\n';
3409  VecFile << InactiveTrackElement.VLoc << '\n';
3410  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3411  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3412  }
3413  Utilities->CallLogPop(449);
3414 }
3415 
3416 // ---------------------------------------------------------------------------
3417 
3418 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3419 {
3420 // VecFile already open and its pointer at right place on calling
3421 // check trackfinished flag
3422 // inactive elements follow immediately after active elements, no need to check for a marker between them
3423  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3424  int TempInt;
3425 
3426  GraphicsFollow = false;
3427  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3428  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3429  {
3430  Utilities->CallLogPop(1513);
3431  return(false);
3432  }
3433 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3434  AnsiString MarkerString;
3435 
3436  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3437  {
3438  Utilities->CallLogPop(1758);
3439  return(false);
3440  }
3441  if(MarkerString[MarkerString.Length()] == '1')
3442  {
3443  GraphicsFollow = true;
3444  }
3445  for(int x = 0; x < NumberOfActiveElements; x++)
3446  {
3447  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3448  {
3449  Utilities->CallLogPop(1759);
3450  return(false);
3451  }
3452  VecFile >> TempInt;
3453  int SpeedTag = TempInt;
3454  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3455  {
3456  Utilities->CallLogPop(1514);
3457  return(false);
3458  }
3459  VecFile >> TempInt;
3460  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3461  {
3462  Utilities->CallLogPop(1495);
3463  return(false);
3464  }
3465  VecFile >> TempInt;
3466  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3467  {
3468  Utilities->CallLogPop(1497);
3469  return(false);
3470  }
3471  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3472  {
3473  VecFile >> TempInt;
3474  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3475  {
3476  Utilities->CallLogPop(1499);
3477  return(false);
3478  }
3479  VecFile >> TempInt;
3480  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3481  {
3482  Utilities->CallLogPop(1500);
3483  return(false);
3484  }
3485  }
3486  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3487  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3488  {
3489  VecFile >> TempInt;
3490  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3491  {
3492  Utilities->CallLogPop(1502);
3493  return(false);
3494  }
3495  }
3496  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3497  {
3498  VecFile >> TempInt;
3499  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3500  {
3501  Utilities->CallLogPop(1155);
3502  return(false);
3503  }
3504  }
3505  VecFile >> TempInt;
3506  if((TempInt < -1) || (TempInt > 999999)) // Length01
3507  {
3508  Utilities->CallLogPop(1503);
3509  return(false);
3510  }
3511  VecFile >> TempInt;
3512  if((TempInt < -1) || (TempInt > 999999)) // Length23
3513  {
3514  Utilities->CallLogPop(1504);
3515  return(false);
3516  }
3517  VecFile >> TempInt;
3518  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3519  {
3520  Utilities->CallLogPop(1505);
3521  return(false);
3522  }
3523  VecFile >> TempInt;
3524  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3525  {
3526  Utilities->CallLogPop(1506);
3527  return(false);
3528  }
3529  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3530  {
3531  Utilities->CallLogPop(1142);
3532  return(false); // LocationName
3533  }
3534  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3535  {
3536  Utilities->CallLogPop(1143);
3537  return(false); // ActiveTrackElementName
3538  }
3539  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3540  {
3541  Utilities->CallLogPop(1787);
3542  return(false); // marker
3543  }
3544  }
3545  int NumberOfInactiveElements = 0;
3546 
3547  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3548  if(NumberOfInactiveElements < 0) // No of active elements
3549  {
3550  Utilities->CallLogPop(1493);
3551  return(false);
3552  }
3553  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3554  {
3555  Utilities->CallLogPop(1764);
3556  return(false); // **Inactive elements** marker
3557  }
3558  for(int x = 0; x < NumberOfInactiveElements; x++)
3559  {
3560  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3561  {
3562  Utilities->CallLogPop(1765);
3563  return(false);
3564  }
3565  VecFile >> TempInt;
3566  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3567  {
3568  Utilities->CallLogPop(1494);
3569  return(false);
3570  }
3571  VecFile >> TempInt;
3572  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3573  {
3574  Utilities->CallLogPop(1496);
3575  return(false);
3576  }
3577  VecFile >> TempInt;
3578  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3579  {
3580  Utilities->CallLogPop(1498);
3581  return(false);
3582  }
3583  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3584  {
3585  Utilities->CallLogPop(1144);
3586  return(false); // LocationName
3587  }
3588  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3589  {
3590  Utilities->CallLogPop(1788);
3591  return(false); // marker
3592  }
3593  }
3594  Utilities->CallLogPop(1507);
3595  return(true);
3596 }
3597 
3598 // ---------------------------------------------------------------------------
3599 
3600 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3601 {
3602  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3603  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3604 
3605  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3606  {
3607  Utilities->CallLogPop(2168);
3608  return(false);
3609  }
3610  // filename in Graphics folder, then HPos, then VPos
3611  AnsiString FileName = "", TempStr = "";
3612 
3613  for(int x = 0; x < NumberOfGraphics; x++)
3614  {
3615  TPicture *TempPicture = new TPicture;
3616  try
3617  {
3618  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3619  {
3620  Utilities->CallLogPop(2169);
3621  delete TempPicture;
3622  return(false);
3623  }
3624  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3625  delete TempPicture;
3626  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3627  {
3628  Utilities->CallLogPop(2170);
3629  return(false);
3630  }
3631  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3632  {
3633  Utilities->CallLogPop(2171);
3634  return(false);
3635  }
3636  }
3637  catch(const EInvalidGraphic &e) //non error catch
3638  {
3639  //move file pointer to end of graphic section for later checks in session files
3640  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3641  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3642  for(int y = x + 1; y < NumberOfGraphics; y++)
3643  {
3644  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3645  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3646  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3647  }
3648  ShowMessage(FileName +
3649  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3650  Utilities->CallLogPop(2172);
3651  delete TempPicture;
3652  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3653  }
3654  catch(const Exception &e) //non error catch
3655  {
3656  //move file pointer to end of graphic section for later checks in session files
3657  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3658  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3659  for(int y = x + 1; y < NumberOfGraphics; y++)
3660  {
3661  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3662  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3663  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3664  }
3665  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3666  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3667  Utilities->CallLogPop(2173);
3668  delete TempPicture;
3669  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3670  }
3671  }
3672  Utilities->CallLogPop(2174);
3673  return(true);
3674 }
3675 
3676 // ---------------------------------------------------------------------------
3677 
3678 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3679 {
3680  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3681  int VecSize = Track->BarriersDownVector.size();
3682 
3683  Utilities->SaveFileInt(OutFile, VecSize);
3684  for(int x = 0; x < VecSize; x++)
3685  {
3687  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3688  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3689  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3690  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3691  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3692  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3693  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3694  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3695  }
3696  Utilities->CallLogPop(1963);
3697 }
3698 
3699 // ---------------------------------------------------------------------------
3700 
3701 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3702 {
3703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3704  int VecSize = Track->ChangingLCVector.size();
3705 
3706  Utilities->SaveFileInt(OutFile, VecSize);
3707  for(int x = 0; x < VecSize; x++)
3708  {
3710  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3711  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3712  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3713  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3714  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3715  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3716  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3717  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3718  }
3719  Utilities->CallLogPop(1980);
3720 }
3721 
3722 // ---------------------------------------------------------------------------
3723 
3724 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3725 {
3726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3727  int VecSize = Utilities->LoadFileInt(VecFile);
3728 
3729  for(int x = 0; x < VecSize; x++)
3730  {
3731  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3732  {
3733  Utilities->CallLogPop(1970);
3734  return(false);
3735  }
3736  if(!Utilities->CheckFileBool(VecFile))
3737  {
3738  Utilities->CallLogPop(1971);
3739  return(false);
3740  }
3741  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3742  {
3743  Utilities->CallLogPop(1972);
3744  return(false);
3745  }
3746  if(!Utilities->CheckFileDouble(VecFile))
3747  {
3748  Utilities->CallLogPop(1973);
3749  return(false);
3750  }
3751  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3752  {
3753  Utilities->CallLogPop(1974);
3754  return(false);
3755  }
3756  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3757  {
3758  Utilities->CallLogPop(1975);
3759  return(false);
3760  }
3761  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3762  {
3763  Utilities->CallLogPop(1976);
3764  return(false);
3765  }
3766  if(!Utilities->CheckFileDouble(VecFile))
3767  {
3768  Utilities->CallLogPop(1977);
3769  return(false);
3770  }
3771  }
3772  Utilities->CallLogPop(1978);
3773  return(true);
3774 }
3775 
3776 // ---------------------------------------------------------------------------
3777 
3778 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3779 {
3780  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3781  int VecSize = Utilities->LoadFileInt(VecFile);
3782 
3783  for(int x = 0; x < VecSize; x++)
3784  {
3785  TActiveLevelCrossing TALC;
3786  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3787  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3788  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3789  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3790  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3791  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3792  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3793  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3794  BarriersDownVector.push_back(TALC);
3795  }
3796  Utilities->CallLogPop(1979);
3797 }
3798 
3799 // ---------------------------------------------------------------------------
3800 
3801 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3802 /*
3803  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3804  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3805  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3806 */
3807 {
3808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3809  TTrackElement Next;
3810 
3811  Track->RebuildUserGraphics(0, HiddenDisplay); //moved here from Clearand... so user graphics overwrites LongServRef names
3813  while(ReturnNextInactiveTrackElement(0, Next))
3814  {
3815  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3816  {
3817  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3818  {
3819  // only plot if on screen, to save time
3820 // if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3821 // ((Next.VLoc - Display->DisplayOffsetV) >= 0) && ((Next.VLoc - Display->DisplayOffsetV) < Utilities->ScreenElementHeight))
3822  {
3823  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3824  }
3825  }
3826  }
3827  }
3828 
3829  NextTrackElementPtr = TrackVector.begin();
3830  while(ReturnNextTrackElement(0, Next))
3831  {
3832  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3833  {
3834 // if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3835 // ((Next.VLoc - Display->DisplayOffsetV) >= 0) && ((Next.VLoc - Display->DisplayOffsetV) < Utilities->ScreenElementHeight))
3836  {
3837  if(Next.TrackType == Points)
3838  {
3839  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3841  {
3842  OneLengthOrSpeedHeatMapColour(0, Next, true, Disp); //true for 01 length
3843  OneLengthOrSpeedHeatMapColour(1, Next, false, Disp); //false for 23 length
3844  }
3845  }
3846  else if(Next.TrackType == SignalPost)
3847  {
3848  PlotSignal(9, Next, Disp);
3850  {
3851  OneLengthOrSpeedHeatMapColour(2, Next, true, Disp); //true for 01 length
3852  }
3853  }
3854  else if(Next.TrackType == GapJump)
3855  {
3856  PlotGap(0, Next, Disp);
3858  {
3859  OneLengthOrSpeedHeatMapColour(3, Next, true, Disp); //true for 01 length
3860  }
3861  }
3862  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3863  {
3864  PlotContinuation(0, Next, Disp);
3866  {
3867  OneLengthOrSpeedHeatMapColour(4, Next, true, Disp); //true for 01 length
3868  }
3869  }
3870  else if(Next.TrackType == Crossover || Next.TrackType == Bridge)
3871  {
3872  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3874  {
3875  OneLengthOrSpeedHeatMapColour(5, Next, true, Disp); //true for 01 length
3876  OneLengthOrSpeedHeatMapColour(6, Next, false, Disp); //false for 23 length
3877  }
3878  }
3879  else
3880  {
3881  Next.PlotVariableTrackElement(13, Disp); // for footcrossings, may be striped or not
3883  {
3884  OneLengthOrSpeedHeatMapColour(7, Next, true, Disp); //true for 01 length
3885  }
3886  }
3887  }
3888  }
3889  }
3890 
3891  if(BothPointFilletsAndBasicLCs)
3892  {
3894  while(ReturnNextInactiveTrackElement(4, Next))
3895  {
3896  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3897  {
3898  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3899  {
3900  // only plot if on screen, to save time, & OK as plotting one by one here
3901 // if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3902 // ((Next.VLoc - Display->DisplayOffsetV) >= 0) && ((Next.VLoc - Display->DisplayOffsetV) < Utilities->ScreenElementHeight))
3903  {
3904  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3905  {
3906  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3907  }
3908  else
3909  {
3910  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3911  }
3912  }
3913  }
3914  }
3915  }
3916  }
3917 
3918  TextHandler->RebuildFromTextVector(1, Disp); // plot text after all else so visible over stations/track etc. //moved from above at v2.20.3
3919  Disp->Update();
3920  Utilities->CallLogPop(468);
3921 }
3922 
3923 // ---------------------------------------------------------------------------
3924 
3925 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3926 {
3927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3928  if(UserGraphicVector.empty())
3929  {
3930  Utilities->CallLogPop(2175);
3931  return;
3932  }
3933  TUserGraphicItem UGI;
3934 
3935  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3936  {
3937  UGI = UserGraphicVectorAt(4, x);
3938  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3939  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3940  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3941  {
3942  Disp->PlotAndAddUserGraphic(0, UGI);
3943  }
3944  }
3945  Disp->Update();
3946  Utilities->CallLogPop(2176);
3947 }
3948 
3949 // ---------------------------------------------------------------------------
3950 
3951 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3952 /*
3953  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3954 */
3955 {
3956  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3957 // need to change graphics back to black on white if have a dark background
3958  TColor OldTransparentColour = Utilities->clTransparent;
3959 
3961  {
3962  Utilities->clTransparent = TColor(0xFFFFFF); // white
3965  }
3966  TTrackElement Next;
3967 
3968  Bitmap->Canvas->CopyMode = cmSrcCopy;
3970  Graphics::TBitmap *GraphicOutput;
3971 
3972  while(ReturnNextInactiveTrackElement(2, Next))
3973  {
3974  GraphicOutput = Next.GraphicPtr;
3975  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3976  {
3977  if(Next.LocationName == "") // plot as named or unnamed (striped)
3978  {
3979  // default is not striped
3980  switch(Next.SpeedTag)
3981  {
3982  case 76: // t platform
3983  GraphicOutput = RailGraphics->gl76Striped;
3984  break;
3985 
3986  case 77: // h platform
3987  GraphicOutput = RailGraphics->bm77Striped;
3988  break;
3989 
3990  case 78: // v platform
3991  GraphicOutput = RailGraphics->bm78Striped;
3992  break;
3993 
3994  case 79: // r platform
3995  GraphicOutput = RailGraphics->gl79Striped;
3996  break;
3997 
3998  case 96: // concourse
3999  GraphicOutput = RailGraphics->ConcourseStriped;
4000  break;
4001 
4002  case 129: // v footbridge
4003  GraphicOutput = RailGraphics->gl129Striped;
4004  break;
4005 
4006  case 130: // h footbridge
4007  GraphicOutput = RailGraphics->gl130Striped;
4008  break;
4009 
4010  case 131: // non-station named loc
4011  GraphicOutput = RailGraphics->bmNameStriped;
4012  break;
4013 
4014  case 145: // v underpass
4015  GraphicOutput = RailGraphics->gl145Striped;
4016  break;
4017 
4018  case 146: // h underpass
4019  GraphicOutput = RailGraphics->gl146Striped;
4020  break;
4021 
4022  default:
4023  GraphicOutput = Next.GraphicPtr;
4024  break;
4025  }
4026  }
4027  if(Next.SpeedTag == 144) // level crossing
4028  {
4029  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
4030  {
4031  GraphicOutput = RailGraphics->LCBothVer;
4032  }
4033  else
4034  {
4035  GraphicOutput = RailGraphics->LCBothHor;
4036  }
4037  }
4038  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4039  }
4040  }
4041 
4042  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
4043 
4044 
4045  NextTrackElementPtr = TrackVector.begin();
4046  while(ReturnNextTrackElement(2, Next))
4047  {
4048  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4049  {
4050  if(Next.TrackType == Points) // plot both fillets
4051  {
4052  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4053  if(Next.SpeedTag < 28)
4054  {
4055  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4057  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4059  }
4060  else if(Next.SpeedTag < 132)
4061  {
4062  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4063  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4064  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4065  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4066  }
4067  else
4068  {
4069  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4070  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4071  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4072  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4073  }
4074  }
4075  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4076  {
4077  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4078  {
4079  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4080  }
4081  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4082  {
4083  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4084  }
4085  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4086  {
4087  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4088  }
4089  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4090  {
4091  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4092  }
4093  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4094  {
4095  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4096  }
4097  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4098  {
4099  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4100  }
4101  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4102  {
4103  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4104  }
4105  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4106  {
4107  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4108  }
4109  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4110  {
4111  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4112  }
4113  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4114  {
4115  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4116  }
4117  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4118  {
4119  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4120  }
4121  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4122  {
4123  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4124  }
4125  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4126  {
4127  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4128  }
4129  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4130  {
4131  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4132  }
4133  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4134  {
4135  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4136  }
4137  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4138  {
4139  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4140  }
4141  }
4142  // below added for version 0.6, only stop signals to be drawn
4143  else if(Next.TrackType == SignalPost)
4144  {
4145  for(int x = 0; x < 40; x++)
4146  {
4147  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4148  {
4149  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4150  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4151  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4152  int HOffset = 0;
4153  if(Next.SpeedTag > 73)
4154  {
4155  HOffset = 5;
4156  }
4157  else if(Next.SpeedTag == 71)
4158  {
4159  HOffset = 9;
4160  }
4161  int VOffset = 0;
4162  if(Next.SpeedTag == 69)
4163  {
4164  VOffset = 9;
4165  }
4166  else if(Next.SpeedTag == 72)
4167  {
4168  VOffset = 5;
4169  }
4170  else if(Next.SpeedTag == 74)
4171  {
4172  VOffset = 5;
4173  }
4174  Graphics::TBitmap *GraphicPtr;
4175  if(Next.SpeedTag > 71)
4176  {
4177  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4178  }
4179  else if(Next.SpeedTag < 70)
4180  {
4181  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4182  }
4183  else
4184  {
4185  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4186  }
4187  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4188  // plot special signal platform if present
4189  Graphics::TBitmap* SignalPlatformGraphic;
4190  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4191  {
4192  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4193  }
4194  // now plot signal (double yellow overwrites most of signal platform if present)
4195  // below amended for version 0.6
4197  {
4198  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4199  }
4200  else if(Next.SigAspect == TTrackElement::TwoAspect)
4201  {
4202  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4203  }
4204  else if(Next.SigAspect == TTrackElement::GroundSignal)
4205  {
4206  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4207  }
4208  else // 4 aspect
4209  {
4210  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4211  }
4212  break;
4213  }
4214  }
4215  }
4216  else
4217  {
4218  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4219  }
4220  }
4221  }
4222  if(OldTransparentColour != clB5G5R5)
4223  {
4224  Utilities->clTransparent = OldTransparentColour; // restore
4227  }
4228  Utilities->CallLogPop(1533);
4229 }
4230 
4231 // ---------------------------------------------------------------------------
4232 
4233 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4234 {
4235  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4236  if(UserGraphicVector.empty())
4237  {
4238  Utilities->CallLogPop(2192);
4239  return;
4240  }
4241  else
4242  {
4243  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4244  {
4245  Bitmap->Canvas->CopyMode = cmSrcCopy;
4246  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4247  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4248  }
4249  }
4250  Utilities->CallLogPop(2193);
4251 }
4252 
4253 // ---------------------------------------------------------------------------
4254 
4255 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4256 /*
4257  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4258  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4259 */
4260 {
4261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4262 // need to change graphics back to black on white if have a dark background
4263  TColor OldTransparentColour = Utilities->clTransparent;
4264 
4266  {
4267  Utilities->clTransparent = TColor(0xFFFFFF); // white
4270  }
4271  TTrackElement Next;
4272 
4273  Bitmap->Canvas->CopyMode = cmSrcCopy;
4275  Graphics::TBitmap *GraphicOutput;
4276 
4277  while(ReturnNextInactiveTrackElement(3, Next))
4278  {
4279  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4280  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4281  {
4282  if(Next.SpeedTag == 144) // level crossing
4283  {
4284  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4285  if(BaseElement == 1) // hor element
4286  {
4287  if(Next.Attribute == 1) // open to trains
4288  {
4289  GraphicOutput = RailGraphics->LCBothHor;
4290  }
4291  else // plot as closed to trains if in any other state
4292  {
4293  GraphicOutput = RailGraphics->LCBothVer;
4294  }
4295  }
4296  else // vert element
4297  {
4298  if(Next.Attribute == 1) // open to trains
4299  {
4300  GraphicOutput = RailGraphics->LCBothVer;
4301  }
4302  else // plot as closed to trains if in any other state
4303  {
4304  GraphicOutput = RailGraphics->LCBothHor;
4305  }
4306  }
4307  }
4308  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4309  }
4310  }
4311 
4312  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4313 
4314  NextTrackElementPtr = TrackVector.begin();
4315  while(ReturnNextTrackElement(3, Next))
4316  {
4317  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4318  {
4319  if(Next.TrackType == Points) // plot active fillet
4320  {
4321  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4322  if(Next.SpeedTag < 28)
4323  {
4324  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4326  }
4327  else if(Next.SpeedTag < 132)
4328  {
4329  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4331  }
4332  else
4333  {
4334  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4336  }
4337  if(Next.Failed) //added at v2.13.0
4338  {
4339  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4341  }
4342 
4343  }
4344  else if(Next.TrackType == GapJump) // plot as connected
4345  {
4346  if(Next.SpeedTag == 88)
4347  {
4348  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4349  }
4350  else if(Next.SpeedTag == 89)
4351  {
4352  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4353  }
4354  else if(Next.SpeedTag == 90)
4355  {
4356  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4357  }
4358  else if(Next.SpeedTag == 91)
4359  {
4360  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4361  }
4362  else if(Next.SpeedTag == 92)
4363  {
4364  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4365  }
4366  else if(Next.SpeedTag == 93)
4367  {
4368  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4369  }
4370  else if(Next.SpeedTag == 94)
4371  {
4372  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4373  }
4374  else if(Next.SpeedTag == 95)
4375  {
4376  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4377  }
4378  }
4379  else if(Next.TrackType == SignalPost) //plot in correct colour
4380  {
4381  for(int x = 0; x < 40; x++)
4382  {
4383  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4384  {
4385  //plot blank first, then plot platform if present - (always not striped for operating railway)
4386  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4387  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4388  int HOffset = 0;
4389  if(Next.SpeedTag > 73)
4390  {
4391  HOffset = 5;
4392  }
4393  else if(Next.SpeedTag == 71)
4394  {
4395  HOffset = 9;
4396  }
4397  int VOffset = 0;
4398  if(Next.SpeedTag == 69)
4399  {
4400  VOffset = 9;
4401  }
4402  else if(Next.SpeedTag == 72)
4403  {
4404  VOffset = 5;
4405  }
4406  else if(Next.SpeedTag == 74)
4407  {
4408  VOffset = 5;
4409  }
4410  Graphics::TBitmap *GraphicPtr;
4411  if(Next.SpeedTag > 71)
4412  {
4413  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4414  }
4415  else if(Next.SpeedTag < 70)
4416  {
4417  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4418  }
4419  else
4420  {
4421  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4422  }
4423  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4424  // plot special signal platform if present
4425  Graphics::TBitmap* SignalPlatformGraphic;
4426  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4427  {
4428  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4429  }
4430  if(!Next.Failed)
4431  {
4432  // now plot signal (double yellow overwrites most of signal platform if present)
4433  // below amended for version 0.6
4435  {
4436  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4437  }
4438  else if(Next.SigAspect == TTrackElement::TwoAspect)
4439  {
4440  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4441  }
4442  else if(Next.SigAspect == TTrackElement::GroundSignal)
4443  {
4444  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4445  }
4446  else // 4 aspect
4447  {
4448  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4449  }
4450  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4451  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4452  {
4453  if(Next.SpeedTag == 68)
4454  {
4455  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4456  }
4457  if(Next.SpeedTag == 69)
4458  {
4459  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4460  }
4461  if(Next.SpeedTag == 70)
4462  {
4463  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4464  }
4465  if(Next.SpeedTag == 71)
4466  {
4467  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4468  }
4469  if(Next.SpeedTag == 72)
4470  {
4471  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4472  }
4473  if(Next.SpeedTag == 73)
4474  {
4475  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4476  }
4477  if(Next.SpeedTag == 74)
4478  {
4479  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4480  }
4481  if(Next.SpeedTag == 75)
4482  {
4483  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4484  }
4485  }
4486  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4487  {
4488  for(int x = 0; x < 40; x++)
4489  {
4490  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4491  {
4492  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4493  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4494  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4495  // plot special signal platform if present
4496  Graphics::TBitmap* SignalPlatformGraphic;
4497  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4498  {
4499  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4500  }
4501  // now plot signal
4502  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4503  break;
4504  }
4505  }
4506  }
4507  break;
4508  }
4509  else //added at v2.13.0
4510  {
4512  {
4513  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4514  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4515  }
4516  else
4517  {
4518  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4519  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4520  }
4521  break;
4522  }
4523  }
4524  }
4525  }
4526  else
4527  {
4528  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4529  if(Next.Failed) //added at v2.13.0
4530  {
4531  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4533  }
4534  }
4535  }
4536  }
4537  if(OldTransparentColour != clB5G5R5)
4538  {
4539  Utilities->clTransparent = OldTransparentColour; // restore
4542  }
4543  Utilities->CallLogPop(1701);
4544 }
4545 
4546 // ---------------------------------------------------------------------------
4547 
4548 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4549 {
4550  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4551  for(unsigned int x = 0; x < TrackVector.size(); x++)
4552  {
4553  if(TrackElementAt(1093, x).TrackType == GapJump)
4554  {
4555  if(TrackElementAt(1094, x).Conn[0] > -1)
4556  {
4557  continue; // to next 'x' value as this element has already been set
4558  }
4559  // here if identify a GapJump element not yet set
4560  GapPos = x;
4561  GapHLoc = TrackElementAt(1095, x).HLoc;
4562  GapVLoc = TrackElementAt(1096, x).VLoc;
4563  // highlight it
4565  Utilities->CallLogPop(469);
4566  return(true);
4567  }
4568  }
4569  Utilities->CallLogPop(470);
4570  return(false);
4571 }
4572 
4573 // ---------------------------------------------------------------------------
4574 
4575 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4576 {
4577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4578  AnsiString(VLoc));
4579  int Position;
4580  TTrackElement TrackElement;
4581 
4582  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4583  {
4584  Utilities->CallLogPop(471);
4585  return(false); // not found
4586  }
4587  if(TrackElement.TrackType != GapJump)
4588  {
4589  Utilities->CallLogPop(472);
4590  return(false); // found something but not a gap
4591  }
4592  if(Position == GapPos)
4593  {
4594  Utilities->CallLogPop(473);
4595  return(false); // selected original gap
4596  }
4597  if(TrackElementAt(1097, Position).Conn[0] != -1)
4598  {
4599  Utilities->CallLogPop(474);
4600  return(false); // already selected
4601  }
4602  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4603  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4604  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4605  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4606 // now highlight the selected location
4607  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4608  Utilities->CallLogPop(475);
4609  return(true);
4610 }
4611 
4612 // ---------------------------------------------------------------------------
4613 
4614 bool TTrack::GapsUnset(int Caller)
4615 // returns true if there are gaps and any are unset
4616 {
4617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4618  if(TrackVector.size() == 0)
4619  {
4620  Utilities->CallLogPop(476);
4621  return(false);
4622  }
4623  for(unsigned int x = 0; x < TrackVector.size(); x++)
4624  {
4625  if(TrackElementAt(1102, x).TrackType == GapJump)
4626  {
4627  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4628  {
4629  Utilities->CallLogPop(477);
4630  return(true);
4631  }
4632  else // set, but may not have matching element, or that element may not be set
4633  {
4634  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4635  // check that the element pointed to by the gap link is a GapJump
4636  {
4637  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4638  Utilities->CallLogPop(1137);
4639  return(false);
4640  }
4641 // here if gap connection is itself a GapJump
4642  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4643  // check that the element pointed to by the gap link is a GapJump & that its gap link
4644  // points back to 'x'
4645  {
4646  Utilities->CallLogPop(478);
4647  return(true);
4648  }
4649 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4650  }
4651  } // if(TrackElementAt(, x).TrackType == GapJump)
4652 
4653  } // for x...
4654  Utilities->CallLogPop(479);
4655  return(false);
4656 }
4657 
4658 // ---------------------------------------------------------------------------
4659 
4660 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4661 {
4662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4663  for(unsigned int x = 0; x < TrackVector.size(); x++)
4664  {
4665  if(TrackElementAt(1110, x).TrackType == GapJump)
4666  {
4667  Utilities->CallLogPop(1105);
4668  return(false);
4669  }
4670  }
4671  Utilities->CallLogPop(1106);
4672  return(true);
4673 }
4674 
4675 // ---------------------------------------------------------------------------
4676 
4677 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4678 {
4679  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4680  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4681  {
4682  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4683  {
4684  Utilities->CallLogPop(1107);
4685  return(false);
4686  }
4687  }
4688  for(unsigned int x = 0; x < TrackVector.size(); x++)
4689  {
4690  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4691  {
4692  Utilities->CallLogPop(1108);
4693  return(false);
4694  }
4695  }
4696  Utilities->CallLogPop(1109);
4697  return(true);
4698 }
4699 
4700 // ---------------------------------------------------------------------------
4701 
4703 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4704 // returns false otherwise or if there are no NamedLocationElements
4705 {
4706  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4707  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4708  {
4709  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4710  {
4711  if(InactiveTrackElementAt(139, x).LocationName == "")
4712  {
4713  Utilities->CallLogPop(1110);
4714  return(true);
4715  }
4716  }
4717  }
4718  for(unsigned int x = 0; x < TrackVector.size(); x++)
4719  {
4720  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4721  {
4722  if(TrackElementAt(1113, x).LocationName == "")
4723  {
4724  Utilities->CallLogPop(1111);
4725  return(true);
4726  }
4727  }
4728  }
4729  Utilities->CallLogPop(1112);
4730  return(false);
4731 }
4732 
4733 // ---------------------------------------------------------------------------
4734 
4735 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4736 {
4737  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4738  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4739  Utilities->CallLogPop(480);
4740 }
4741 
4742 // ---------------------------------------------------------------------------
4743 
4745 {
4746  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4747  if(TrackVector.size() == 0)
4748  {
4749  Utilities->CallLogPop(481);
4750  return;
4751  }
4752  for(unsigned int x = 0; x < TrackVector.size(); x++)
4753  {
4754  if(TrackElementAt(1114, x).TrackType == GapJump)
4755  {
4756  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4757  {
4758  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4759  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4760  {
4761  TrackElementAt(1118, x).Conn[0] = -1;
4762  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4763  continue; // to next 'x'
4764  }
4765 // here if gap connection is itself a GapJump
4766  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4767  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4768  // if not clear Conns & CLks
4769  {
4770  TrackElementAt(1121, x).Conn[0] = -1;
4771  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4772  continue; // to next 'x'
4773  }
4774 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4775 // hence no more action needed on these Conns & CLks
4776  }
4777  } // else //gap jump
4778 
4779  } // for x...
4780 // throw Exception("Test Exception");//test
4781  Utilities->CallLogPop(482);
4782 }
4783 
4784 // ---------------------------------------------------------------------------
4785 
4786 void TTrack::ResetSignals(int Caller)
4787 {
4788  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4789  for(unsigned int x = 0; x < TrackVector.size(); x++)
4790  {
4791  if(TrackElementAt(1123, x).TrackType == SignalPost)
4792  {
4793  TrackElementAt(1124, x).Attribute = 0;
4794  TrackElementAt(1514, x).Failed = false;
4795  TrackElementAt(1682, x).CallingOnSet = false; //added at v2.20.3 to clear position light signals
4796  }
4797  }
4798  FailedSignalsVector.clear();
4799  Utilities->CallLogPop(483);
4800 }
4801 
4802 // ---------------------------------------------------------------------------
4803 
4804 void TTrack::ResetPoints(int Caller)
4805 {
4806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4807  for(unsigned int x = 0; x < TrackVector.size(); x++)
4808  {
4809  if((TrackElementAt(1125, x).TrackType == Points) && (TrackElementAt(1571, x).Failed))
4810  {
4811  TrackElementAt(1126, x).Attribute = 0;
4812  TrackElementAt(1515, x).Failed = false;
4815  TrackElementAt(1569, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4816  TrackElementAt(1570, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 = -1; //added at v2.15.0
4817  }
4818  }
4819  FailedPointsVector.clear();
4820  Utilities->CallLogPop(484);
4821 }
4822 
4823 // ---------------------------------------------------------------------------
4824 
4825 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4826 {
4827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4828  for(unsigned int x = 0; x < TrackVector.size(); x++)
4829  {
4830  if((TrackElementAt(1554, x).TrackType == Simple) && (TrackElementAt(1555, x).Failed))
4831  {
4832  TrackElementAt(1556, x).Failed = false;
4834  TrackElementAt(1573, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4835  }
4836  }
4837  TSRVector.clear();
4838  Utilities->CallLogPop(2550);
4839 }
4840 
4841 // ---------------------------------------------------------------------------
4842 
4843 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4844 {
4845  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4846  if(TrackVector.empty())
4847  {
4848  TrackMap.clear();
4849  Utilities->CallLogPop(485);
4850  return(true);
4851  }
4852 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4853  THVPair TrackMapKeyPair;
4854 
4855  NewVector.clear();
4856  TTrackMapIterator TrackMapPtr;
4857 
4858  if(!TrackMap.empty())
4859  {
4860  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4861  {
4862  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4863  }
4864  }
4865  if(NewVector.size() != TrackMap.size())
4866  {
4867  throw Exception("Error - Map & Vector different sizes");
4868  }
4869  unsigned int NonZeroCount = 0;
4870 
4871  for(unsigned int x = 0; x < TrackVector.size(); x++)
4872  {
4873  if(TrackElementAt(1127, x).TrackType != Erase)
4874  {
4875  NonZeroCount++;
4876  }
4877  }
4878  if(NewVector.size() != NonZeroCount)
4879  {
4880  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4881  }
4883  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4884  TTrackMapEntry TrackMapEntry;
4885 
4886  for(unsigned int x = 0; x < TrackVector.size(); x++)
4887  {
4888  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4889  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4890  TrackMapEntry.first = TrackMapKeyPair;
4891  TrackMapEntry.second = x;
4892  if(!(TrackMap.insert(TrackMapEntry).second))
4893  {
4894  throw Exception("Error - map insertion failure, TrackVector in error");
4895  }
4896  }
4897 // All track now relocated in TrackVector, reset all Conns & CLks
4898  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4899  {
4900  for(unsigned int y = 0; y < 4; y++)
4901  {
4902  TrackElementAt(1130, x).Conn[y] = -1;
4903  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4904  }
4905  }
4906  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4907  CheckMapAndTrack(4); // test
4908  CheckMapAndInactiveTrack(4); // test
4909  CheckLocationNameMultiMap(8); // test
4910  if(!ResetGapsFromGapMap(1))
4911  {
4912  Utilities->CallLogPop(489);
4913  return(false);
4914  }
4915  Utilities->CallLogPop(490);
4916  return(true);
4917 }
4918 
4919 // ---------------------------------------------------------------------------
4920 
4921 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4922 {
4923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4924  GapMap.clear();
4925  THVPair GapMapKeyPair, GapMapValuePair;
4926  TGapMapEntry GapMapEntry;
4927 
4928  for(unsigned int x = 0; x < TrackVector.size(); x++)
4929  {
4930  if(TrackElementAt(1132, x).TrackType == GapJump)
4931  {
4932  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4933  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4934  GapMapEntry.first = GapMapKeyPair;
4935  if(TrackElementAt(1135, x).Conn[0] == -1)
4936  {
4937  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4938  }
4939  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4940  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4941  GapMapEntry.second = GapMapValuePair;
4942  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4943  {
4944  GapMap.insert(GapMapEntry);
4945  }
4946  }
4947  }
4948  Utilities->CallLogPop(492);
4949 }
4950 
4951 // ---------------------------------------------------------------------------
4952 
4953 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4954 {
4955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4956 
4957 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4958  LocError = false;
4959  bool TrackElementPositionsOK = true;
4960 
4961  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4962  {
4963  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4964  {
4965  continue; // skip blank elements
4966  }
4967 // check footcrossing linkages
4968  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4969  {
4970  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4971  {
4972  ShowMessage(
4973  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4974  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4975  "can't connect to an underpass or vice versa)");
4976  HLoc = TrackElementAt(1141, x).HLoc;
4977  VLoc = TrackElementAt(1142, x).VLoc;
4978  LocError = true;
4979  Utilities->CallLogPop(493);
4980  return(false);
4981  }
4982  }
4983  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4984  {
4985  if(TrackElementAt(1143, x).Link[y] <= 0)
4986  {
4987  continue; // no link
4988  }
4989  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4990  {
4991  continue; // buffer
4992  }
4993  if(TrackElementAt(1146, x).Config[y] == Gap)
4994  {
4995  continue; // gaps set later from GapMap
4996  }
4997  // get required H & V for track element joining link 'y'
4998  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4999  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
5000  // find track element if present
5001  bool ConnectionFoundFlag;
5002  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
5003  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5004  {
5005  ShowMessage("Can't have a track element adjacent to a continuation exit");
5006  HLoc = TrackElementAt(1152, x).HLoc;
5007  VLoc = TrackElementAt(1153, x).VLoc;
5008  LocError = true;
5009  if(FinalCall)
5010  {
5011  throw Exception("Error in final track linkage - continuation adjacent to another element");
5012  }
5013  Utilities->CallLogPop(1539);
5014  return(false);
5015  }
5016  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
5017  {
5018  continue;
5019  }
5020  if(ConnectionFoundFlag)
5021  {
5022  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
5023  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
5024 
5025  bool ExitSignal = false;
5026  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
5027  {
5028  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
5029  {
5030  ExitSignal = true;
5031  }
5032  }
5033  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
5034  {
5035  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
5036  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
5037  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
5038  TrackElementPositionsOK = false;
5039  }
5040  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
5041  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
5042  {
5043  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
5044  // need room for a train (2 elements) without fouling points or signals
5045  TrackElementPositionsOK = false;
5046  }
5047  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
5048  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
5049  {
5050  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
5051  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5052  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5053  // be named but needs the adjacent element named too
5054  TrackElementPositionsOK = false;
5055  }
5056  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5057  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5058  {
5059  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5060  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5061  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5062  TrackElementPositionsOK = false;
5063  }
5064 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5065 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !Utilities->OverrideAndHideSignalBridgeMessage)
5066  {
5067  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5068  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5069  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5070  TrackElementPositionsOK = false;
5071  }*/
5072  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !Utilities->OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5073  {
5074  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5075  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5076  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5077  TrackElementPositionsOK = false;
5078  }
5079  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5080  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5081  {
5082  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5083  TrackElementPositionsOK = false;
5084  }
5085  // if failed then set the invert values for the offending element
5086  if(!TrackElementPositionsOK)
5087  {
5088  HLoc = TrackElementAt(1183, x).HLoc;
5089  VLoc = TrackElementAt(1184, x).VLoc;
5090  LocError = true;
5091  if(FinalCall)
5092  {
5093  throw Exception("Error in track element positions in FinalCall");
5094  }
5095  Utilities->CallLogPop(494);
5096  return(false);
5097  }
5098  }
5099  // no 'else' here, if there's no link then will be picked up in 2nd pass
5100  }
5101  } // for(unsigned int x=0;x<TrackVector.size();x++)
5102 
5103 
5104 //2nd pass - looking for missing connections
5105  LocError = false;
5106  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5107  {
5108  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5109  {
5110  continue; // skip blank elements
5111  }
5112  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5113  {
5114  if(TrackElementAt(1440, x).Link[y] <= 0)
5115  {
5116  continue; // no link
5117  }
5118  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5119  {
5120  continue; // buffer
5121  }
5122  if(TrackElementAt(1443, x).Config[y] == Gap)
5123  {
5124  continue; // gaps set later from GapMap
5125  }
5126  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5127  {
5128  continue; //continuation
5129  }
5130  // get required H & V for track element joining link 'y'
5131  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5132  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5133  // find track element if present
5134  bool ConnectionFoundFlag;
5135  bool LinkMatchFound = false;
5136  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag); //this is the joining element at link 'y'
5137  // if there isn't a connection set the invert values for the offending element
5138  if(ConnectionFoundFlag) //set the ConnLinkPos values
5139  {
5140  for(unsigned int a = 0; a < 4; a++) //links for the joining element at this element's link 'y'
5141  {
5142  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5143  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5144  {
5145  TrackElementAt(1182, x).ConnLinkPos[y] = a; //for points, 'y == 0' and 'y == 2' will be allocated same value for 'a'
5146  LinkMatchFound = true;
5147  break; //can only match 1 so can break
5148  }
5149  }
5150  if(!LinkMatchFound)
5151  {
5152  HLoc = TrackElementAt(1446, x).HLoc;
5153  VLoc = TrackElementAt(1447, x).VLoc;
5154  LocError = true;
5155  if(FinalCall)
5156  {
5157  throw Exception("Error in final track linkage - - no matching link found");
5158  }
5159  Utilities->CallLogPop(495);
5160  return(false);
5161  }
5162  }
5163  else //error
5164  {
5165  HLoc = TrackElementAt(1185, x).HLoc;
5166  VLoc = TrackElementAt(1186, x).VLoc;
5167  LocError = true;
5168  if(FinalCall)
5169  {
5170  throw Exception("Error in final track linkage - connection not found");
5171  }
5172  Utilities->CallLogPop(2443);
5173  return(false);
5174  }
5175  }
5176  }
5177 //end of 2nd pass
5178 
5179  if(FinalCall)
5180  {
5183  }
5184 
5185 // confirmatiory checks that all ok - or throw error
5186  bool ConnErrorFlag = false;
5187 
5188  for(unsigned int x = 0; x < TrackVector.size(); x++)
5189  {
5190  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5191  {
5192  ConnErrorFlag = true;
5193  }
5194  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5195  {
5196  ConnErrorFlag = true;
5197  }
5198  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5199  {
5200  ConnErrorFlag = true;
5201  }
5202  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5203  {
5204  ConnErrorFlag = true;
5205  }
5206  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5207  {
5208  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5209  {
5210  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1) ||
5211  (TrackElementAt(1637, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1638, x).StationEntryStopLinkPos4 != -1))
5212  {
5213  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5214  }
5215  }
5216  }
5217  }
5218  if(ConnErrorFlag)
5219  {
5220  if(FinalCall)
5221  {
5222  throw Exception("ConnError in LinkTrack - Final");
5223  }
5224  else
5225  {
5226  throw Exception("ConnError in LinkTrack - Precheck");
5227  }
5228  }
5229  bool CLkErrorFlag = false;
5230 
5231  for(unsigned int x = 0; x < TrackVector.size(); x++)
5232  {
5233  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5234  {
5235  CLkErrorFlag = true;
5236  }
5237  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5238  {
5239  CLkErrorFlag = true;
5240  }
5241  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5242  {
5243  CLkErrorFlag = true;
5244  }
5245  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5246  {
5247  CLkErrorFlag = true;
5248  }
5249  }
5250 
5251  if(CLkErrorFlag)
5252  {
5253  if(FinalCall)
5254  {
5255  throw Exception("CLkError in LinkTrack - Final");
5256  }
5257  else
5258  {
5259  throw Exception("CLkError in LinkTrack - Precheck");
5260  }
5261  }
5262 
5263 // set element lengths to min of 10m
5264  for(unsigned int x = 0; x < TrackVector.size(); x++)
5265  {
5266  if(TrackElementAt(1214, x).TrackType == Erase)
5267  {
5268  continue; // skip blank elements
5269  }
5270  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5271  {
5272  TrackElementAt(1216, x).Length01 = 10;
5273  }
5274  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5275  {
5276  TrackElementAt(1219, x).Length23 = 10;
5277  }
5278  }
5279 
5280  if(FinalCall) // ONLY at FinalCall, no point calling twice
5281  {
5282  CalcHLocMinEtc(3);
5283  }
5284 
5285  Utilities->CallLogPop(497);
5286  return(true);
5287 }
5288 
5289 // ---------------------------------------------------------------------------
5290 
5291 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5292 {
5293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5294  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5295  {
5296  if(TrackElementAt(1220, x).TrackType == Erase)
5297  {
5298  continue; // skip blank elements
5299 
5300  }
5301 // check footcrossing linkages
5302  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5303  {
5304  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5305  {
5306  Utilities->CallLogPop(1127);
5307  return(false);
5308  }
5309  }
5310  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5311  {
5312  if(TrackElementAt(1223, x).Link[y] <= 0)
5313  {
5314  continue; // no link
5315  }
5316  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5317  {
5318  continue; // buffer
5319  }
5320  if(TrackElementAt(1226, x).Config[y] == Gap)
5321  {
5322  continue; // gaps set later from GapMap
5323 
5324  }
5325  // get required H & V for track element joining link 'y'
5326  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5327  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5328  // find track element if present
5329  bool ConnectionFoundFlag;
5330  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5331  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5332  {
5333  if(FinalCall)
5334  {
5335  throw Exception("Error in final track linkage - continuation adjacent to another element");
5336  }
5337  Utilities->CallLogPop(1540);
5338  return(false);
5339  }
5340  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5341  {
5342  continue;
5343  }
5344  if(ConnectionFoundFlag)
5345  {
5346  TrackElementAt(1234, x).Conn[y] = VecPos;
5347  bool LinkFoundFlag = false;
5348  // find connecting link in the newly found track element if there is one & make checks
5349  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5350  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5351  {
5352  Utilities->CallLogPop(1541);
5353  return(false);
5354  }
5355  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5356  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5357  {
5358  Utilities->CallLogPop(1542);
5359  return(false);
5360  }
5361  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5362  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5363  {
5364  Utilities->CallLogPop(1543);
5365  return(false);
5366  }
5367  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5368  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5369  {
5370  Utilities->CallLogPop(1981);
5371  return(false);
5372  }
5373 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5374  else if(TrackElementAt(, x).TrackType == Continuation)
5375  {
5376  int H = TrackElementAt(, x).HLoc;
5377  int V = TrackElementAt(, x).VLoc;
5378  bool FoundFlag = false;
5379  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5380  if(FoundFlag)
5381  {
5382  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5383  {
5384  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5385  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5386  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5387  if(FoundFlag)
5388  {
5389  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5390  {
5391  Utilities->CallLogPop();
5392  return false;
5393  }
5394  }
5395  else
5396  {
5397  Utilities->CallLogPop();
5398  return false;
5399  }
5400  }
5401  }
5402  }
5403 */
5404  for(unsigned int a = 0; a < 4; a++)
5405  {
5406  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5407  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5408  {
5409  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5410  // note - this ensures that if the connecting element is a leading point
5411  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5412  // (Points have the same link value for both [0] and [2])
5413  LinkFoundFlag = true;
5414  break; // stop after first find or will find later link for leading point
5415  }
5416  }
5417  if(!LinkFoundFlag)
5418  {
5419  if(FinalCall)
5420  {
5421  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5422  }
5423  Utilities->CallLogPop(1128);
5424  return(false);
5425  }
5426  }
5427  else // if(ConnectionFoundFlag)
5428  {
5429  if(FinalCall)
5430  {
5431  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5432  }
5433  Utilities->CallLogPop(1129);
5434  return(false);
5435  }
5436  }
5437  } // for(unsigned int x=0;x<TrackVector.size();x++)
5438 
5439  if(FinalCall)
5440  {
5443  }
5444 // final check
5445  bool ConnErrorFlag = false;
5446 
5447  for(unsigned int x = 0; x < TrackVector.size(); x++)
5448  {
5449  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5450  {
5451  ConnErrorFlag = true;
5452  }
5453  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5454  {
5455  ConnErrorFlag = true;
5456  }
5457  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5458  {
5459  ConnErrorFlag = true;
5460  }
5461  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5462  {
5463  ConnErrorFlag = true;
5464  }
5465  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5466  {
5467  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5468  {
5469  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1) ||
5470  (TrackElementAt(1639, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1640, x).StationEntryStopLinkPos4 != -1))
5471  {
5472  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5473  }
5474  }
5475  }
5476  }
5477  if(ConnErrorFlag)
5478  {
5479  if(FinalCall)
5480  {
5481  throw Exception("ConnError in LinkTrack - Final");
5482  }
5483  else
5484  {
5485  throw Exception("ConnError in LinkTrack - Precheck");
5486  }
5487  }
5488  bool CLkErrorFlag = false;
5489 
5490  for(unsigned int x = 0; x < TrackVector.size(); x++)
5491  {
5492  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5493  {
5494  CLkErrorFlag = true;
5495  }
5496  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5497  {
5498  CLkErrorFlag = true;
5499  }
5500  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5501  {
5502  CLkErrorFlag = true;
5503  }
5504  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5505  {
5506  CLkErrorFlag = true;
5507  }
5508  }
5509 
5510  if(CLkErrorFlag)
5511  {
5512  if(FinalCall)
5513  {
5514  throw Exception("CLkError in LinkTrack - Final");
5515  }
5516  else
5517  {
5518  throw Exception("CLkError in LinkTrack - Precheck");
5519  }
5520  }
5521 // set element lengths to min of 10m
5522  for(unsigned int x = 0; x < TrackVector.size(); x++)
5523  {
5524  if(TrackElementAt(1284, x).TrackType == Erase)
5525  {
5526  continue; // skip blank elements
5527  }
5528  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5529  {
5530  TrackElementAt(1286, x).Length01 = 10;
5531  }
5532  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5533  {
5534  TrackElementAt(1289, x).Length23 = 10;
5535  }
5536  }
5537 
5538  if(FinalCall) // ONLY at FinalCall, no point calling twice
5539  {
5540  CalcHLocMinEtc(7);
5541  }
5542  Utilities->CallLogPop(1130);
5543  return(true);
5544 }
5545 
5546 // ---------------------------------------------------------------------------
5547 
5548 bool TTrack::IsTrackLinked(int Caller) // not used any more
5549 {
5550  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5551  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5552  {
5553  if(TrackElementAt(1290, x).TrackType == Erase)
5554  {
5555  Utilities->CallLogPop(498);
5556  return(false);
5557  }
5558 // check foot linkages
5559  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5560  {
5561  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5562  {
5563  Utilities->CallLogPop(499);
5564  return(false);
5565  }
5566  }
5567  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5568  {
5569  if(TrackElementAt(1293, x).Link[y] <= 0)
5570  {
5571  continue; // no link
5572  }
5573  if(TrackElementAt(1294, x).Config[y] == End)
5574  {
5575  continue; // buffer or continuation
5576  }
5577  if(TrackElementAt(1295, x).Config[y] == Gap)
5578  {
5579  continue; // gaps set later from GapMap
5580 
5581  }
5582  // get required H & V for track element joining link 'y'
5583  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5584  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5585  // find track element if present
5586  bool ConnectionFoundFlag = false;
5587  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5588  if(ConnectionFoundFlag)
5589  {
5590  TrackElementAt(1300, x).Conn[y] = VecPos;
5591  // find connecting link in the newly found track element if there is one & make buffer check
5592  bool LinkFoundFlag = false;
5593  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5594  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5595  {
5596  Utilities->CallLogPop(500);
5597  return(false);
5598  }
5599  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5600  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5601  {
5602  Utilities->CallLogPop(501);
5603  return(false);
5604  }
5605  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5606  {
5607  Utilities->CallLogPop(502);
5608  return(false);
5609  }
5610  else
5611  {
5612  for(unsigned int a = 0; a < 4; a++)
5613  {
5614  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5615  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5616  {
5617  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5618  // note - this ensures that if the connecting element is a leading point
5619  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5620  // (Points have the same link value for both [0] and [2])
5621  LinkFoundFlag = true;
5622  break; // stop after first find or will find later link for leading point
5623  }
5624  }
5625  }
5626  if(!LinkFoundFlag)
5627  {
5628  Utilities->CallLogPop(503);
5629  return(false);
5630  }
5631  }
5632  else // if(ConnectionFoundFlag)
5633  {
5634  Utilities->CallLogPop(504);
5635  return(false);
5636  }
5637  }
5638  } // for(unsigned int x=0;x<TrackVector.size();x++)
5639 
5640 // final check
5641  bool ConnErrorFlag = false;
5642 
5643  for(unsigned int x = 0; x < TrackVector.size(); x++)
5644  {
5645  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5646  {
5647  ConnErrorFlag = true;
5648  }
5649  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5650  {
5651  ConnErrorFlag = true;
5652  }
5653  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5654  {
5655  ConnErrorFlag = true;
5656  }
5657  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5658  {
5659  ConnErrorFlag = true;
5660  }
5661  }
5662  if(ConnErrorFlag)
5663  {
5664  Utilities->CallLogPop(505);
5665  return(false);
5666  }
5667  bool CLkErrorFlag = false;
5668 
5669  for(unsigned int x = 0; x < TrackVector.size(); x++)
5670  {
5671  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5672  {
5673  CLkErrorFlag = true;
5674  }
5675  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5676  {
5677  CLkErrorFlag = true;
5678  }
5679  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5680  {
5681  CLkErrorFlag = true;
5682  }
5683  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5684  {
5685  CLkErrorFlag = true;
5686  }
5687  }
5688 
5689  if(CLkErrorFlag)
5690  {
5691  Utilities->CallLogPop(506);
5692  return(false);
5693  }
5694  Utilities->CallLogPop(507);
5695  return(true);
5696 }
5697 
5698 // ---------------------------------------------------------------------------
5699 
5701 {
5702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5703  int Position1, Position2;
5704  TTrackElement TrackElement1, TrackElement2;
5705  TGapMapIterator GapMapPtr;
5706 
5707  if(!GapMap.empty())
5708  {
5709  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5710  {
5711  int HLoc1 = GapMapPtr->first.first;
5712  int VLoc1 = GapMapPtr->first.second;
5713  int HLoc2 = GapMapPtr->second.first;
5714  int VLoc2 = GapMapPtr->second.second;
5715  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5716  {
5717  throw Exception("Failed to find H & V for gap1, GapMap in error");
5718  }
5719  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5720  {
5721  throw Exception("Failed to find H & V for gap2, GapMap in error");
5722  }
5723  if(TrackElementAt(9, Position1).TrackType != GapJump)
5724  {
5725  throw Exception("Element at Pos1 not a gap, GapMap in error");
5726  }
5727  if(TrackElementAt(10, Position2).TrackType != GapJump)
5728  {
5729  throw Exception("Element at Pos2 not a gap, GapMap in error");
5730  }
5731  TrackElementAt(11, Position1).Conn[0] = Position2;
5732  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5733  TrackElementAt(13, Position2).Conn[0] = Position1;
5734  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5735  }
5736  }
5737  Utilities->CallLogPop(510);
5738  return(true);
5739 }
5740 
5741 // ---------------------------------------------------------------------------
5742 
5743 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5744 {
5745 // TIMPair MapEntry;
5746  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5747  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5748  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5749  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5750  TLocationNameMultiMapEntry LocationNameEntry;
5751 
5752  LocationNameEntry.first = TrackElement.LocationName;
5753  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5754  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5755  {
5756 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5757 // could arise when loading old railways with multiple NonStationNamedLocs
5758  bool FoundFlag = false;
5759  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5760  if(FoundFlag)
5761  {
5762  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5763  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5764  {
5765  Utilities->CallLogPop(1813);
5766  return;
5767  }
5768  }
5769  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5770  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5771  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5772  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5773  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5774  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5775  if(TrackElement.FixedNamedLocationElement)
5776  {
5777  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5778  LocationNameMultiMap.insert(LocationNameEntry);
5779  }
5780  if(TrackElement.HLoc < HLocMin)
5781  {
5782  HLocMin = TrackElement.HLoc;
5783  }
5784  if(TrackElement.HLoc > HLocMax)
5785  {
5786  HLocMax = TrackElement.HLoc;
5787  }
5788  if(TrackElement.VLoc < VLocMin)
5789  {
5790  VLocMin = TrackElement.VLoc;
5791  }
5792  if(TrackElement.VLoc > VLocMax)
5793  {
5794  VLocMax = TrackElement.VLoc;
5795  }
5796  }
5797  else
5798  {
5799 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5800 // shouldn't arise but leave in as a safeguard
5801  bool FoundFlag = false;
5802  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5803  if(FoundFlag)
5804  {
5805  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5806  {
5807  Utilities->CallLogPop(1814);
5808  return;
5809  }
5810  }
5811  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5812  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5813  {
5814  TrackMapKeyPair.first = TrackElement.HLoc;
5815  TrackMapKeyPair.second = TrackElement.VLoc;
5816  TrackMapEntry.first = TrackMapKeyPair;
5817  TrackMapEntry.second = TrackVector.size() - 1;
5818  TrackMap.insert(TrackMapEntry);
5819  if(TrackElement.FixedNamedLocationElement)
5820  {
5821  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5822  LocationNameMultiMap.insert(LocationNameEntry);
5823  }
5824  if(TrackElement.HLoc < HLocMin)
5825  {
5826  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5827  }
5828  if(TrackElement.HLoc > HLocMax)
5829  {
5830  HLocMax = TrackElement.HLoc;
5831  }
5832  if(TrackElement.VLoc < VLocMin)
5833  {
5834  VLocMin = TrackElement.VLoc;
5835  }
5836  if(TrackElement.VLoc > VLocMax)
5837  {
5838  VLocMax = TrackElement.VLoc;
5839  }
5840  }
5841  }
5842 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5843 // CheckMapAndInactiveTrack(6);//test
5844 
5845 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5846 // with the Platforms until layout fully loaded
5847  Utilities->CallLogPop(511);
5848 }
5849 
5850 // ---------------------------------------------------------------------------
5851 
5852 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5853 {
5854  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5855  AnsiString(VLoc));
5856  THVPair TrackMapKeyPair;
5857 
5858  FoundFlag = false;
5859  TTrackMapIterator TrackMapPtr;
5860 
5861  TrackMapKeyPair.first = HLoc;
5862  TrackMapKeyPair.second = VLoc;
5863  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5864  if(TrackMapPtr == TrackMap.end())
5865  {
5866  Utilities->CallLogPop(512);
5867  return(-1); // nothing found
5868  }
5869  else
5870  {
5871  FoundFlag = true;
5872  Utilities->CallLogPop(513);
5873  return(TrackMapPtr->second);
5874  }
5875 }
5876 
5877 // ---------------------------------------------------------------------------
5878 
5879 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5880 {
5881  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5882  AnsiString(VLoc));
5883  THVPair TrackMapKeyPair;
5884  TTrackMapIterator TrackMapPtr;
5885 
5886  TrackMapKeyPair.first = HLoc;
5887  TrackMapKeyPair.second = VLoc;
5888  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5889  if(TrackMapPtr == TrackMap.end())
5890  {
5891  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5892  throw Exception(Message);
5893  }
5894  else
5895  {
5896  Utilities->CallLogPop(1943);
5897  return(TrackElementAt(871, TrackMapPtr->second));
5898  }
5899 }
5900 
5901 // ---------------------------------------------------------------------------
5902 
5903 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5904 { //modded at v2.9.2 to make Map & Vector references
5905  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5906  AnsiString(VLoc));
5907  THVPair MapKeyPair;
5908  TTrackMapIterator MapPtr;
5909 
5910  MapKeyPair.first = HLoc;
5911  MapKeyPair.second = VLoc;
5912  MapPtr = Map.find(MapKeyPair);
5913  if(MapPtr == Map.end())
5914  {
5915  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5916  throw Exception(Message);
5917  }
5918  else
5919  {
5920  Utilities->CallLogPop(2280);
5921  return(Vector.at(MapPtr->second));
5922  }
5923 }
5924 
5925 // ---------------------------------------------------------------------------
5926 
5928 {
5929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5930  AnsiString(VLoc));
5931  THVPair InactiveTrackMapKeyPair;
5932  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5933 
5934  InactiveTrackMapKeyPair.first = HLoc;
5935  InactiveTrackMapKeyPair.second = VLoc;
5936  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5937  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5938  {
5939  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5940  throw Exception(Message);
5941  }
5942  else
5943  {
5944  Utilities->CallLogPop(1949);
5945  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5946  }
5947 }
5948 
5949 // ---------------------------------------------------------------------------
5950 
5951 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5952 {
5953  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5954  bool Present = true;
5955  THVPair TrackMapKeyPair;
5956  TTrackMapIterator TrackMapPtr;
5957 
5958  TrackMapKeyPair.first = HLoc;
5959  TrackMapKeyPair.second = VLoc;
5960  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5961  if(TrackMapPtr == TrackMap.end())
5962  {
5963  Present = false;
5964  }
5965  Utilities->CallLogPop(2057);
5966  return(Present);
5967 }
5968 
5969 // ---------------------------------------------------------------------------
5970 
5971 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5972 {
5973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5974  AnsiString(VLoc));
5975  bool Present = true;
5976  THVPair InactiveTrackMapKeyPair;
5977  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5978 
5979  InactiveTrackMapKeyPair.first = HLoc;
5980  InactiveTrackMapKeyPair.second = VLoc;
5981  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5982  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5983  {
5984  Present = false;
5985  }
5986  Utilities->CallLogPop(2058);
5987  return(Present);
5988 }
5989 
5990 // ---------------------------------------------------------------------------
5991 
5992 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5993 // max number of elements is 2, for platforms
5994 // note that both elements of RetPair may be the same, if only one present in map
5995 {
5996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5997  AnsiString(VLoc));
5998  THVPair InactiveTrackMapKeyPair;
5999  TIMPair RetPair;
6000  TInactiveTrackRange InactiveTrackRange;
6001 
6002  FoundFlag = false;
6003  InactiveTrackMapKeyPair.first = HLoc;
6004  InactiveTrackMapKeyPair.second = VLoc;
6005  if(InactiveTrack2MultiMap.empty())
6006  {
6007  RetPair.first = 0;
6008  RetPair.second = 0;
6009  Utilities->CallLogPop(1815);
6010  return(RetPair); // map empty
6011  }
6012  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
6013  if(InactiveTrackRange.first == InactiveTrackRange.second)
6014  {
6015  RetPair.first = 0;
6016  RetPair.second = 0;
6017  Utilities->CallLogPop(514);
6018  return(RetPair); // nothing found
6019  }
6020  else
6021  {
6022  RetPair.first = InactiveTrackRange.first->second;
6023  RetPair.second = (--InactiveTrackRange.second)->second;
6024  FoundFlag = true;
6025  Utilities->CallLogPop(515);
6026  return(RetPair);
6027  }
6028 }
6029 
6030 // ---------------------------------------------------------------------------
6031 
6032 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
6033 {
6034 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
6035  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
6036  AnsiString(DivergingPosition));
6037  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
6038  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
6039  int SpeedTag1 = T1.SpeedTag;
6040  int SpeedTag2 = T2.SpeedTag;
6041 
6042  if((T1.Attribute) != (T2.Attribute))
6043  {
6044  Utilities->CallLogPop(516);
6045  return(false);
6046  }
6047  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
6048  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
6049  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
6050  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
6051  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
6052  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6053  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6054  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6055  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6056  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6057  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6058  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6059  {
6060  Utilities->CallLogPop(517);
6061  return(true);
6062  }
6063  else
6064  {
6065  Utilities->CallLogPop(518);
6066  return(false);
6067  }
6068 }
6069 
6070 // ---------------------------------------------------------------------------
6071 
6072 /*
6073  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6074  {
6075  if(lower.second < higher.second) return true;
6076  else if(lower.second > higher.second) return false;
6077  else if(lower.second == higher.second)
6078  {
6079  if(lower.first < higher.first) return true;
6080  }
6081  return false;
6082  }
6083 */
6084 // ---------------------------------------------------------------------------
6085 
6086 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6087 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6088 {
6089  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6090  if(TrackElement.TrackType != GapJump)
6091  {
6092  throw Exception("Error, Wrong track type in PlotGap");
6093  }
6094  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6095  {
6096  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6097  }
6098  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6099  {
6100  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6101  }
6102  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6103  {
6104  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6105  }
6106  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6107  {
6108  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6109  }
6110  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6111  {
6112  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6113  }
6114  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6115  {
6116  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6117  }
6118  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6119  {
6120  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6121  }
6122  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6123  {
6124  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6125  }
6126  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6127  {
6128  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6129  }
6130  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6131  {
6132  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6133  }
6134  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6135  {
6136  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6137  }
6138  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6139  {
6140  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6141  }
6142  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6143  {
6144  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6145  }
6146  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6147  {
6148  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6149  }
6150  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6151  {
6152  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6153  }
6154  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6155  {
6156  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6157  }
6158  Utilities->CallLogPop(1101);
6159 }
6160 
6161 // ---------------------------------------------------------------------------
6162 
6163 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6164 {
6165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6166  TrackElement.PlotVariableTrackElement(7, Disp);
6167  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6168  {
6169  THVPair PosPair;
6170  PosPair.first = TrackElement.HLoc;
6171  PosPair.second = TrackElement.VLoc;
6172  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6173  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6174  {
6175  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6176  }
6177  }
6178  Utilities->CallLogPop(2403);
6179 }
6180 
6181 // ---------------------------------------------------------------------------
6182 
6183 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6184 {
6185  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6186  if(TrackElement.TrackType != Points)
6187  {
6188  throw Exception("Error, Wrong track type in PlotPoints");
6189  }
6190  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6191  //check if a blue location and if so plot the blue element again - named or not as appropriate - added at v2.18.0 for blue locs at points
6192  bool FoundFlag = false;
6193  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(32, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6194  if(IMPair.first > 0) //can only have one entry in IMPair for points
6195  {
6196  TTrackElement ITE = InactiveTrackElementAt(1409, IMPair.first);
6197  if(ITE.SpeedTag == 131)
6198  {
6199  ITE.PlotVariableTrackElement(8, Disp); //plot the blue square again
6200  }
6201  }
6202  TrackElement.PlotVariableTrackElement(4, Disp);
6203  if(BothFillets)
6204  {
6205  if(TrackElement.SpeedTag < 28)
6206  {
6207  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6208  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6209  }
6210  else if(TrackElement.SpeedTag < 132)
6211  {
6212  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6213  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6214  }
6215  else
6216  {
6217  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6218  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6219  }
6220  }
6221  else if(!TrackElement.Failed) //not failed
6222  {
6223  if(TrackElement.SpeedTag < 28)
6224  {
6225  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6226  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6227  }
6228  else if(TrackElement.SpeedTag < 132)
6229  {
6230  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6231  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6232  }
6233  else
6234  {
6235  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6236  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6237  }
6238  }
6239  else //failed in fixed position
6240  {
6241  if(TrackElement.SpeedTag < 28)
6242  {
6243  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6244  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6245  }
6246  else if(TrackElement.SpeedTag < 132)
6247  {
6248  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6249  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6250  }
6251  else
6252  {
6253  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6254  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6255  }
6256  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6257  }
6258 // replot platform if required
6259  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6260  bool BlueLoc = false;
6261  if(FoundFlag)
6262  {
6263  TTrackElement TE = GetInactiveTrackElementFromTrackMap(6, TrackElement.HLoc, TrackElement.VLoc);
6264  if(TE.SpeedTag == 131) //non-station named location - don't want to replot these or the track is obscured - added at v2.18.0
6265  {
6266  BlueLoc = true;
6267  }
6268  }
6269  if(FoundFlag && !BlueLoc)
6270  {
6271  // only one platform possible at points so only need to plot IMPair.first
6272  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6273  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6274  }
6275  Utilities->CallLogPop(519);
6276 }
6277 
6278 // ---------------------------------------------------------------------------
6279 
6280 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6281 {
6282 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6283  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6284  bool FoundFlag = false;
6285  if(TrackElement.TrackType != SignalPost)
6286  {
6287  throw Exception("Error, Wrong track type in PlotSignal");
6288  }
6289  if(!TrackElement.Failed) //added at v2.13.0
6290  {
6291  for(int x = 0; x < 40; x++)
6292  {
6293  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6294  {
6295  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6296  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6297  // in case existing signal is a double yellow
6298  // plot platforms if present
6299  // Graphics::TBitmap* SignalPlatformGraphic;
6300  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6301  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6302  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6303  // to not be plotted with the above function.
6304 
6305  //replot the blue square to cover the blank area - added at v2.18.0
6306  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(36, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6307  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6308  {
6309  TTrackElement ITE = InactiveTrackElementAt(1414, IMPair.first);
6310  if(ITE.SpeedTag == 131)
6311  {
6312  ITE.PlotVariableTrackElement(9, Disp); //plot the blue square again to cover the blank area
6313  }
6314  }
6315 
6316  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6317  // now plot signal (double yellow overwrites most of signal platform if present)
6318  // additions at version 0.6 for other aspects & ground sigs
6319  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6320  {
6321  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6322  }
6323  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6324  {
6325  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6326  }
6327  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6328  {
6329  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6330  }
6331  else // 4 aspect
6332  {
6333  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6334  }
6335  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6336  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6337  {
6338  if(TrackElement.SpeedTag == 68)
6339  {
6340  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6341  }
6342  if(TrackElement.SpeedTag == 69)
6343  {
6344  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6345  }
6346  if(TrackElement.SpeedTag == 70)
6347  {
6348  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6349  }
6350  if(TrackElement.SpeedTag == 71)
6351  {
6352  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6353  }
6354  if(TrackElement.SpeedTag == 72)
6355  {
6356  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6357  }
6358  if(TrackElement.SpeedTag == 73)
6359  {
6360  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6361  }
6362  if(TrackElement.SpeedTag == 74)
6363  {
6364  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6365  }
6366  if(TrackElement.SpeedTag == 75)
6367  {
6368  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6369  }
6370  }
6371  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6372  // ground signal calling on, need to use normal proceed aspect
6373  {
6374  for(int x = 0; x < 40; x++)
6375  {
6376  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6377  {
6378  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6379  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6380  // plot special signal platform if present
6381  Graphics::TBitmap* SignalPlatformGraphic;
6382  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(37, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6383  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6384  {
6385  TTrackElement ITE = InactiveTrackElementAt(1415, IMPair.first);
6386  if(ITE.SpeedTag == 131)
6387  {
6388  ITE.PlotVariableTrackElement(10, Disp); //plot the blue square again to cover the blank area
6389  }
6390  }
6391  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6392  // now plot signal
6393  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6394  }
6395  }
6396  }
6397  break;
6398  }
6399  }
6400  }
6401  else //failed added at v2.13.0
6402  {
6403  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6404  {
6405  for(int x = 0; x < 8; x++)
6406  {
6407  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6408  {
6409  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6410  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6411  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(38, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6412  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6413  {
6414  TTrackElement ITE = InactiveTrackElementAt(1416, IMPair.first);
6415  if(ITE.SpeedTag == 131)
6416  {
6417  ITE.PlotVariableTrackElement(11, Disp); //plot the blue square again to cover the blank area
6418  }
6419  }
6420  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6421  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6422  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6423  break;
6424  }
6425  }
6426  }
6427  else
6428  {
6429  for(int x = 0; x < 8; x++)
6430  {
6431  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6432  {
6433  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6434  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6435  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(39, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6436  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6437  {
6438  TTrackElement ITE = InactiveTrackElementAt(1417, IMPair.first);
6439  if(ITE.SpeedTag == 131)
6440  {
6441  ITE.PlotVariableTrackElement(12, Disp); //plot the blue square again to cover the blank area
6442  }
6443  }
6444  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6445  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6446  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6447  break;
6448  }
6449  }
6450  }
6451  }
6452  Utilities->CallLogPop(520);
6453 }
6454 
6455 // ---------------------------------------------------------------------------
6456 
6457 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6458 {
6459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6460  bool FoundFlag;
6461  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6462 
6463  if(!FoundFlag)
6464  {
6465  Utilities->CallLogPop(2112);
6466  return;
6467  }
6468  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6469  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6470 
6471  // don't want 'else if' for the below as may need to plot 2 platforms
6472  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6473  {
6474  if(IAElement1.LocationName == "") // '2' will be same
6475  {
6476  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6477  }
6478  else
6479  {
6480  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6481  }
6482  }
6483  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6484  {
6485  if(IAElement1.LocationName == "") // '2' will be same
6486  {
6487  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6488  }
6489  else
6490  {
6491  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6492  }
6493  }
6494  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6495  {
6496  if(IAElement1.LocationName == "") // '2' will be same
6497  {
6498  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6499  }
6500  else
6501  {
6502  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6503  }
6504  }
6505  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6506  {
6507  if(IAElement1.LocationName == "") // '2' will be same
6508  {
6509  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6510  }
6511  else
6512  {
6513  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6514  }
6515  }
6516  Utilities->CallLogPop(2113);
6517 }
6518 
6519 // ---------------------------------------------------------------------------
6520 
6521 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6522 {
6523 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6524  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6525  AnsiString(VLoc));
6526 // find topmost LC, opening them all (to trains) in turn
6527  int UpStep = 0;
6528 
6529  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6530  {
6531  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6532  UpStep--;
6533  }
6534 // now find bottommost LC, opening them all (to trains) in turn
6535  int DownStep = 1;
6536 
6537  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6538  {
6539  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6540  DownStep++;
6541  }
6542 // find leftmost LC, opening them all (to trains) in turn
6543  int LeftStep = 0;
6544 
6545  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6546  {
6547  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6548  LeftStep--;
6549  }
6550 // now find rightmost LC, opening them all (to trains) in turn
6551  int RightStep = 1;
6552 
6553  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6554  {
6555  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6556  RightStep++;
6557  }
6558  Utilities->CallLogPop(1915);
6559 }
6560 
6561 // ---------------------------------------------------------------------------
6562 
6563 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6564 {
6565  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6566 // work upwards setting all to manual
6567  int UpStep = -1;
6568 
6569  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6570  {
6571  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6572  UpStep--;
6573  }
6574 // work downwards setting all to manual
6575  int DownStep = 1;
6576 
6577  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6578  {
6579  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6580  DownStep++;
6581  }
6582 // work leftwards setting all to manual
6583  int LeftStep = -1;
6584 
6585  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6586  {
6587  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6588  LeftStep--;
6589  }
6590 // work rightwards setting all to manual
6591  int RightStep = 1;
6592 
6593  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6594  {
6595  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6596  RightStep++;
6597  }
6598  Utilities->CallLogPop(2242);
6599 }
6600 
6601 // ---------------------------------------------------------------------------
6602 
6603 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6604 {
6605  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6606  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6607  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6608  {
6609  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6610  {
6611  BarriersDownVector.at(x).TypeOfRoute = 2;
6612  break;
6613  }
6614  }
6615  Utilities->CallLogPop(2243);
6616 }
6617 
6618 // ---------------------------------------------------------------------------
6619 
6620 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6621 {
6622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6623 // work upwards
6624  int UpStep = 0; //start with this location
6625 
6626  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6627  {
6628  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6629  {
6630  Utilities->CallLogPop(2244);
6631  return(true);
6632  }
6633  UpStep--;
6634  }
6635 // work downwards
6636  int DownStep = 1;
6637 
6638  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6639  {
6640  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6641  {
6642  Utilities->CallLogPop(2245);
6643  return(true);
6644  }
6645  DownStep++;
6646  }
6647 // work leftwards
6648  int LeftStep = -1;
6649 
6650  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6651  {
6652  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6653  {
6654  Utilities->CallLogPop(2246);
6655  return(true);
6656  }
6657  LeftStep--;
6658  }
6659 // work rightwards
6660  int RightStep = 1;
6661 
6662  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6663  {
6664  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6665  {
6666  Utilities->CallLogPop(2247);
6667  return(true);
6668  }
6669  RightStep++;
6670  }
6671  Utilities->CallLogPop(2248);
6672  return(false);
6673 }
6674 
6675 // ---------------------------------------------------------------------------
6676 
6677 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6678 {
6679  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6680  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6681  {
6682  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6683  {
6684  BDVectorPos = x;
6685  Utilities->CallLogPop(2249);
6686  return(true);
6687  }
6688  }
6689  BDVectorPos = -1;
6690  Utilities->CallLogPop(2250);
6691  return(false);
6692 }
6693 
6694 // ---------------------------------------------------------------------------
6695 
6696 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6697 // open to trains
6698 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6699 {
6700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6701  AnsiString(VLoc));
6702  if(!IsLCAtHV(4, HLoc, VLoc))
6703  {
6704  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6705  }
6706  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6707  {
6708  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6709  }
6710 // check for adjacent LCs & if so open (to trains)
6711  if(BaseElementSpeedTag == 1) // hor track element
6712  {
6713  // find topmost LC, opening them all (to trains) in turn
6714  int UpStep = 0;
6715  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6716  {
6717  UpStep--;
6718  }
6719  UpStep++;
6720  // now find bottommost LC, opening them all (to trains) in turn
6721  int DownStep = 1;
6722  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6723  {
6724  DownStep++;
6725  }
6726  DownStep--;
6727  // now plot graphics, UpStep is smallest & DownStep largest
6728  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6729  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6730  Graphics::TBitmap *RouteGraphic;
6731  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6732  if(TypeOfRoute == 1)
6733  {
6734  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6735  }
6736  else if(TypeOfRoute == 0)
6737  {
6738  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6739  }
6740  else //manual - no route
6741  {
6742  RouteGraphic = BaseGraphic;
6743  }
6744 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6745 // LinkSigRouteGraphicsPtr[1] ver }
6746 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6747 // LinkNonSigRouteGraphicsPtr[1] ver }
6748 
6749  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6750  {
6751  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6752  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6753  if(!Manual)
6754  {
6755  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6756  }
6757  else
6758  {
6759  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6760  }
6761  }
6762  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6763  {
6764  if(UpStep == 0)
6765  {
6766  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6767  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6768  if(!Manual)
6769  {
6770  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6771  }
6772  else
6773  {
6774  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6775  }
6776  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6777  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6778  if(!Manual)
6779  {
6780  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6781  }
6782  else
6783  {
6784  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6785  }
6786  }
6787  else
6788  {
6789  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6790  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6791  if(!Manual)
6792  {
6793  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6794  }
6795  else
6796  {
6797  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6798  }
6799  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6800  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6801  if(!Manual)
6802  {
6803  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6804  }
6805  else
6806  {
6807  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6808  }
6809  }
6810  }
6811  else // at least one plain graphic
6812  {
6813  if(UpStep == 0)
6814  {
6815  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6816  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6817  if(!Manual)
6818  {
6819  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6820  }
6821  else
6822  {
6823  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6824  }
6825  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6826  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6827  if(!Manual)
6828  {
6829  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6830  }
6831  else
6832  {
6833  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6834  }
6835  }
6836  else if(DownStep == 0)
6837  {
6838  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6839  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6840  if(!Manual)
6841  {
6842  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6843  }
6844  else
6845  {
6846  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6847  }
6848  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6849  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6850  if(!Manual)
6851  {
6852  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6853  }
6854  else
6855  {
6856  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6857  }
6858  }
6859  else
6860  {
6861  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6862  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6863  if(!Manual)
6864  {
6865  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6866  }
6867  else
6868  {
6869  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6870  }
6871  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6872  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6873  if(!Manual)
6874  {
6875  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6876  }
6877  else
6878  {
6879  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6880  }
6881  }
6882  for(int x = (UpStep + 1); x < DownStep; x++)
6883  {
6884  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6885  if(x == 0)
6886  {
6887  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6888  }
6889  else
6890  {
6891  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6892  }
6893  if(!Manual)
6894  {
6895  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6896  }
6897  else
6898  {
6899  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6900  }
6901  }
6902  }
6903  Disp->Update();
6904  Utilities->CallLogPop(1958);
6905  return;
6906  }
6907 
6908  else // ver track element
6909  {
6910  // find leftmost LC, opening them all (to trains) in turn
6911  int LStep = 0;
6912  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6913  {
6914  LStep--;
6915  }
6916  LStep++;
6917  // now find rightmost LC, opening them all (to trains) in turn
6918  int RStep = 1;
6919  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6920  {
6921  RStep++;
6922  }
6923  RStep--;
6924  // now plot graphics, LStep is smallest & RStep largest
6925  Graphics::TBitmap *RouteGraphic;
6926  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6927  if(TypeOfRoute == 1)
6928  {
6929  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6930  }
6931  else if(TypeOfRoute == 0)
6932  {
6933  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6934  }
6935  else //manual
6936  {
6937  RouteGraphic = BaseGraphic;
6938  }
6939 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6940 // LinkSigRouteGraphicsPtr[1] ver }
6941 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6942 // LinkNonSigRouteGraphicsPtr[1] ver }
6943  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6944  {
6945  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6946  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6947  if(!Manual)
6948  {
6949  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6950  }
6951  else
6952  {
6953  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6954  }
6955  }
6956  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6957  {
6958  if(LStep == 0)
6959  {
6960  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6961  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6962  if(!Manual)
6963  {
6964  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6965  }
6966  else
6967  {
6968  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6969  }
6970  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6971  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6972  if(!Manual)
6973  {
6974  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6975  }
6976  else
6977  {
6978  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6979  }
6980  }
6981  else
6982  {
6983  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6984  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6985  if(!Manual)
6986  {
6987  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6988  }
6989  else
6990  {
6991  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6992  }
6993  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6994  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6995  if(!Manual)
6996  {
6997  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6998  }
6999  else
7000  {
7001  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7002  }
7003  }
7004  }
7005  else // at least one plain graphic
7006  {
7007  if(LStep == 0)
7008  {
7009  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7010  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
7011  if(!Manual)
7012  {
7013  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7014  }
7015  else
7016  {
7017  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7018  }
7019  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7020  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7021  if(!Manual)
7022  {
7023  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7024  }
7025  else
7026  {
7027  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7028  }
7029  }
7030  else if(RStep == 0)
7031  {
7032  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7033  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7034  if(!Manual)
7035  {
7036  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7037  }
7038  else
7039  {
7040  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7041  }
7042  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7043  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
7044  if(!Manual)
7045  {
7046  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7047  }
7048  else
7049  {
7050  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7051  }
7052  }
7053  else
7054  {
7055  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7056  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7057  if(!Manual)
7058  {
7059  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7060  }
7061  else
7062  {
7063  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7064  }
7065  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7066  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7067  if(!Manual)
7068  {
7069  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7070  }
7071  else
7072  {
7073  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7074  }
7075  }
7076  for(int x = (LStep + 1); x < RStep; x++)
7077  {
7078  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7079  if(x == 0)
7080  {
7081  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
7082  }
7083  else
7084  {
7085  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
7086  }
7087  if(!Manual)
7088  {
7089  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7090  }
7091  else
7092  {
7093  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7094  }
7095  }
7096  }
7097  Disp->Update();
7098  Utilities->CallLogPop(1896);
7099  return;
7100  }
7101 }
7102 
7103 // ---------------------------------------------------------------------------
7104 
7105 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
7106 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7107 {
7108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
7109  AnsiString(HLoc) + "," + AnsiString(VLoc));
7110  if(!IsLCAtHV(29, HLoc, VLoc))
7111  {
7112  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7113  }
7114  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7115  {
7116  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7117  }
7118 // check for adjacent LCs & if so open (to trains)
7119  if(BaseElementSpeedTag == 1) // hor track element
7120  {
7121  // find topmost LC, opening them all (to trains) in turn
7122  int UpStep = 0;
7123  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7124  {
7125  UpStep--;
7126  }
7127  UpStep++;
7128  // now find bottommost LC, opening them all (to trains) in turn
7129  int DownStep = 1;
7130  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7131  {
7132  DownStep++;
7133  }
7134  DownStep--;
7135  // now plot graphics, UpStep is smallest & DownStep largest
7136  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7137  {
7138  if(!Manual)
7139  {
7140  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7141  }
7142  else
7143  {
7144  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7145  }
7146  }
7147  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7148  {
7149  if(!Manual)
7150  {
7151  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7152  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7153  }
7154  else
7155  {
7156  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7157  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7158  }
7159  }
7160  else // at least one plain graphic
7161  {
7162  if(!Manual)
7163  {
7164  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7165  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7166  for(int x = (UpStep + 1); x < DownStep; x++)
7167  {
7168  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7169  }
7170  }
7171  else
7172  {
7173  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7174  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7175  for(int x = (UpStep + 1); x < DownStep; x++)
7176  {
7177  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7178  }
7179  }
7180  }
7181  // set markers
7182  for(int x = UpStep; x <= DownStep; x++)
7183  {
7184  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7185  }
7186  Display->Update();
7187  Utilities->CallLogPop(1944);
7188  return;
7189  }
7190 
7191  else // ver track element
7192  {
7193  // find leftmost LC, opening them all (to trains) in turn
7194  int LStep = 0;
7195  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7196  {
7197  LStep--;
7198  }
7199  LStep++;
7200  // now find rightmost LC, opening them all (to trains) in turn
7201  int RStep = 1;
7202  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7203  {
7204  RStep++;
7205  }
7206  RStep--;
7207  // now plot graphics, LStep is smallest & RStep largest
7208  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7209  {
7210  if(!Manual)
7211  {
7212  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7213  }
7214  else
7215  {
7216  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7217  }
7218  }
7219  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7220  {
7221  if(!Manual)
7222  {
7223  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7224  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7225  }
7226  else
7227  {
7228  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7229  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7230  }
7231  }
7232  else // at least one plain graphic
7233  {
7234  if(!Manual)
7235  {
7236  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7237  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7238  for(int x = (LStep + 1); x < RStep; x++)
7239  {
7240  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7241  }
7242  }
7243  else
7244  {
7245  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7246  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7247  for(int x = (LStep + 1); x < RStep; x++)
7248  {
7249  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7250  }
7251  }
7252  }
7253  // set markers
7254  for(int x = LStep; x <= RStep; x++)
7255  {
7256  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7257  }
7258  Disp->Update();
7259  Utilities->CallLogPop(1945);
7260  return;
7261  }
7262 }
7263 
7264 // ---------------------------------------------------------------------------
7265 
7266 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7267 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7268 {
7269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7270  AnsiString(VLoc));
7271  if(!IsLCAtHV(9, HLoc, VLoc))
7272  {
7273  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7274  }
7275  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7276  {
7277  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7278  }
7279 // check for adjacent LCs & if so close (to trains)
7280  if(BaseElementSpeedTag == 1) // hor track element
7281  {
7282  // find topmost LC, closing them all (to trains) in turn
7283  int UpStep = 0;
7284  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7285  {
7286  UpStep--;
7287  }
7288  UpStep++;
7289  // now find bottommost LC, opening them all (to trains) in turn
7290  int DownStep = 1;
7291  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7292  {
7293  DownStep++;
7294  }
7295  DownStep--;
7296  // now plot graphics, UpStep is smallest & DownStep largest
7297  for(int x = UpStep; x < (DownStep + 1); x++)
7298  {
7299  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7300  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7301  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7302  }
7303  Disp->Update();
7304  Utilities->CallLogPop(1959);
7305  return;
7306  }
7307 
7308  else // ver track element
7309  {
7310  // find leftmost LC, closing them all (to trains) in turn
7311  int LStep = 0;
7312  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7313  {
7314  LStep--;
7315  }
7316  LStep++;
7317  // now find rightmost LC, opening them all (to trains) in turn
7318  int RStep = 1;
7319  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7320  {
7321  RStep++;
7322  }
7323  RStep--;
7324  // now plot graphics, LStep is smallest & RStep largest
7325  for(int x = LStep; x < (RStep + 1); x++)
7326  {
7327  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7328  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7329  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7330  }
7331  Disp->Update();
7332  Utilities->CallLogPop(1960);
7333  return;
7334  }
7335 }
7336 
7337 // ---------------------------------------------------------------------------
7338 
7339 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7340 // closed to trains
7341 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7342 {
7343  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7344  AnsiString(HLoc) + "," + AnsiString(VLoc));
7345  if(!IsLCAtHV(34, HLoc, VLoc))
7346  {
7347  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7348  }
7349  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7350  {
7351  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7352  }
7353  TTrackElement TE;
7354 
7355 // check for adjacent LCs & if so close (to trains)
7356  if(BaseElementSpeedTag == 1) // hor track element
7357  {
7358  // find topmost LC, closing them all (to trains) in turn
7359  int UpStep = 0;
7360  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7361  {
7362  UpStep--;
7363  }
7364  UpStep++;
7365  // now find bottommost LC, opening them all (to trains) in turn
7366  int DownStep = 1;
7367  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7368  {
7369  DownStep++;
7370  }
7371  DownStep--;
7372  // now plot graphics, UpStep is smallest & DownStep largest
7373  for(int x = UpStep; x <= DownStep; x++)
7374  {
7375  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7376  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7377  }
7378  Display->Update();
7379  Utilities->CallLogPop(1946);
7380  return;
7381  }
7382 
7383  else // ver track element
7384  {
7385  // find leftmost LC, closing them all (to trains) in turn
7386  int LStep = 0;
7387  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7388  {
7389  LStep--;
7390  }
7391  LStep++;
7392  // now find rightmost LC, opening them all (to trains) in turn
7393  int RStep = 1;
7394  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7395  {
7396  RStep++;
7397  }
7398  RStep--;
7399  // now plot graphics, LStep is smallest & RStep largest
7400  for(int x = LStep; x <= RStep; x++)
7401  {
7402  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7403  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7404  }
7405  Display->Update();
7406  Utilities->CallLogPop(1947);
7407  return;
7408  }
7409 }
7410 
7411 // ---------------------------------------------------------------------------
7412 
7413 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7414 {
7415  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7416  Graphics::TBitmap *RouteGraphic;
7417  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7418 
7419  if(BaseElementSpeedTag == 1)
7420  {
7421  if(TypeOfRoute == 1)
7422  {
7423  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7424  }
7425  else if(TypeOfRoute == 0)
7426  {
7427  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7428  }
7429  else //manual
7430  {
7431  RouteGraphic = BaseGraphic;
7432  }
7433  if(State == Raising)
7434  {
7435  RouteGraphic = BaseGraphic;
7436  }
7437  }
7438  else
7439  {
7440  BaseGraphic = RailGraphics->gl2;
7441  if(TypeOfRoute == 1)
7442  {
7443  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7444  }
7445  else if(TypeOfRoute == 0)
7446  {
7447  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7448  }
7449  else
7450  {
7451  RouteGraphic = BaseGraphic; //manual
7452  }
7453  if(State == Raising)
7454  {
7455  RouteGraphic = BaseGraphic;
7456  }
7457  }
7458  int UpStep = 0;
7459 
7460  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7461  {
7462  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7463  if(UpStep == 0)
7464  {
7465  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7466  }
7467  else
7468  {
7469  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7470  }
7471  UpStep--;
7472  }
7473 // now find bottommost LC, opening them all (to trains) in turn
7474  int DownStep = 1;
7475 
7476  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7477  {
7478  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7479  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7480  DownStep++;
7481  }
7482  int LeftStep = 0;
7483 
7484  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7485  {
7486  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7487  if(LeftStep == 0)
7488  {
7489  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7490  }
7491  else
7492  {
7493  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7494  }
7495  LeftStep--;
7496  }
7497 // now find rightmost LC, opening them all (to trains) in turn
7498  int RightStep = 1;
7499 
7500  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7501  {
7502  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7503  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7504  RightStep++;
7505  }
7506  Disp->Update();
7507  Utilities->CallLogPop(1914);
7508 }
7509 
7510 // ---------------------------------------------------------------------------
7511 
7512 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7513 {
7514 // return false for no LC there, flashing or a closed (to trains) LC
7515  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7516  bool FoundFlag;
7517  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7518 
7519  if(!FoundFlag)
7520  {
7521  Utilities->CallLogPop(1898);
7522  return(false);
7523  }
7524  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7525  {
7526  Utilities->CallLogPop(1899);
7527  return(false);
7528  }
7529  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7530  {
7531  Utilities->CallLogPop(1900);
7532  return(true);
7533  }
7534  Utilities->CallLogPop(1901);
7535  return(false);
7536 }
7537 
7538 // ---------------------------------------------------------------------------
7539 
7540 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7541 {
7542 // return false for no LC there, flashing LC or open (to trains) LC
7543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7544  bool FoundFlag;
7545  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7546 
7547  if(!FoundFlag)
7548  {
7549  Utilities->CallLogPop(1922);
7550  return(false);
7551  }
7552  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7553  {
7554  Utilities->CallLogPop(1923);
7555  return(false);
7556  }
7557  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7558  {
7559  Utilities->CallLogPop(1924);
7560  return(true);
7561  }
7562  Utilities->CallLogPop(1925);
7563  return(false);
7564 }
7565 
7566 // ---------------------------------------------------------------------------
7567 
7568 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7569 {
7570 // return true for barrier in process of moving
7571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7572  bool FoundFlag;
7573  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7574 
7575  if(!FoundFlag)
7576  {
7577  Utilities->CallLogPop(1918);
7578  return(false);
7579  }
7580  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7581  {
7582  Utilities->CallLogPop(1919);
7583  return(false);
7584  }
7585  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7586  {
7587  Utilities->CallLogPop(1920);
7588  return(true);
7589  }
7590  Utilities->CallLogPop(1921);
7591  return(false);
7592 }
7593 
7594 // ---------------------------------------------------------------------------
7595 
7596 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7597 {
7598 // return true for an LC at H&V
7599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7600  bool FoundFlag;
7601  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7602 
7603  if(!FoundFlag)
7604  {
7605  Utilities->CallLogPop(1902);
7606  return(false);
7607  }
7608  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7609  {
7610  Utilities->CallLogPop(1903);
7611  return(false);
7612  }
7613  Utilities->CallLogPop(1904);
7614  return(true);
7615 }
7616 
7617 // ---------------------------------------------------------------------------
7618 
7619 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7620 {
7621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7622  AnsiString(Attr));
7623  bool FoundFlag;
7624  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7625 
7626  if(!FoundFlag)
7627  {
7628  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7629  }
7630  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7631  {
7632  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7633  }
7634  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7635  Utilities->CallLogPop(1905);
7636  return;
7637 }
7638 
7639 // ---------------------------------------------------------------------------
7640 
7642 {
7643  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7644  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7645  {
7646  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7647  if(InactiveTrackElement.TrackType == LevelCrossing)
7648  {
7649  InactiveTrackElementAt(141, x).Attribute = 0;
7650  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7651  }
7652  }
7653  Utilities->CallLogPop(1913);
7654  return;
7655 }
7656 
7657 // ---------------------------------------------------------------------------
7658 
7659 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7660 {
7661 // return true if there is either a route set or being set on any element or a train on any element
7662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7663  "," + AnsiString(VLoc));
7664 
7665  THVPair TrackMapKeyPair;
7666  TTrack::TTrackMapIterator TrackMapPtr;
7667  int DummyRouteNumber;
7668 
7669  TrainPresent = false;
7670 // find topmost LC, checking each for routes & trains
7671  int UpStep = 0;
7672 
7673  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7674  {
7675  TrackMapKeyPair.first = HLoc;
7676  TrackMapKeyPair.second = VLoc + UpStep;
7677  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7678  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7679  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7680  {
7681  Utilities->CallLogPop(1932);
7682  return(true);
7683  }
7684  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7685  {
7686  TrainPresent = true;
7687  Utilities->CallLogPop(1933);
7688  return(true);
7689  }
7690  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7691  {
7692  Utilities->CallLogPop(2274);
7693  return(true);
7694  }
7695  UpStep--;
7696  }
7697 // now find bottommost LC, opening them all (to trains) in turn
7698  int DownStep = 1;
7699 
7700  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7701  {
7702  TrackMapKeyPair.first = HLoc;
7703  TrackMapKeyPair.second = VLoc + DownStep;
7704  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7705  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7706  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7707  {
7708  Utilities->CallLogPop(1934);
7709  return(true);
7710  }
7711  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7712  {
7713  TrainPresent = true;
7714  Utilities->CallLogPop(1935);
7715  return(true);
7716  }
7717  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7718  {
7719  Utilities->CallLogPop(2275);
7720  return(true);
7721  }
7722  DownStep++;
7723  }
7724 // find leftmost LC
7725  int LeftStep = 0;
7726 
7727  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7728  {
7729  TrackMapKeyPair.first = HLoc + LeftStep;
7730  TrackMapKeyPair.second = VLoc;
7731  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7732  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7733  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7734  {
7735  Utilities->CallLogPop(1936);
7736  return(true);
7737  }
7738  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7739  {
7740  TrainPresent = true;
7741  Utilities->CallLogPop(1937);
7742  return(true);
7743  }
7744  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7745  {
7746  Utilities->CallLogPop(2276);
7747  return(true);
7748  }
7749  LeftStep--;
7750  }
7751 // now find rightmost LC, opening them all (to trains) in turn
7752  int RightStep = 1;
7753 
7754  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7755  {
7756  TrackMapKeyPair.first = HLoc + RightStep;
7757  TrackMapKeyPair.second = VLoc;
7758  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7759  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7760  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7761  {
7762  Utilities->CallLogPop(1938);
7763  return(true);
7764  }
7765  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7766  {
7767  TrainPresent = true;
7768  Utilities->CallLogPop(1939);
7769  return(true);
7770  }
7771  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7772  {
7773  Utilities->CallLogPop(2277);
7774  return(true);
7775  }
7776  RightStep++;
7777  }
7778  Utilities->CallLogPop(1940);
7779  return(false);
7780 }
7781 
7782 // ---------------------------------------------------------------------------
7783 
7784 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7785 {
7786  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7787  for(unsigned int x = 0; x < SearchVector.size(); x++)
7788  {
7789  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7790  {
7791  Utilities->CallLogPop(2278);
7792  return(true);
7793  }
7794  }
7795  Utilities->CallLogPop(2279);
7796  return(false);
7797 }
7798 
7799 // ---------------------------------------------------------------------------
7800 
7801 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7802 {
7803  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7804  AnsiString(HLoc) + "," + AnsiString(VLoc));
7805  if(!IsLCAtHV(60, HLoc, VLoc))
7806  {
7807  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7808  }
7809 
7810 // check for adjacent LCs
7811  // find topmost LC
7812  int UpStep = 0;
7813  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7814  {
7815  UpStep--;
7816  }
7817  UpStep++;
7818  // now find bottommost LC, opening them all (to trains) in turn
7819  int DownStep = 1;
7820  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7821  {
7822  DownStep++;
7823  }
7824  DownStep--;
7825  // now plot graphics, UpStep is smallest & DownStep largest
7826  for(int x = UpStep; x <= DownStep; x++)
7827  {
7828  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7829  }
7830 
7831  // find leftmost LC, closing them all (to trains) in turn
7832  int LStep = 0;
7833  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7834  {
7835  LStep--;
7836  }
7837  LStep++;
7838  // now find rightmost LC, opening them all (to trains) in turn
7839  int RStep = 1;
7840  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7841  {
7842  RStep++;
7843  }
7844  RStep--;
7845  // now plot graphics, LStep is smallest & RStep largest
7846  for(int x = LStep; x <= RStep; x++)
7847  {
7848  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7849  }
7850  Display->Update();
7851  Utilities->CallLogPop(2315);
7852  return;
7853 }
7854 
7855 // ---------------------------------------------------------------------------
7856 
7857 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7858 {
7859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7860  if(TrackElement.TrackType != Points)
7861  {
7862  throw Exception("Error, Wrong track type in GetFilletGraphic");
7863  }
7864  if(TrackElement.SpeedTag < 28)
7865  {
7866  Utilities->CallLogPop(521);
7867  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7868  }
7869  else if(TrackElement.SpeedTag < 132)
7870  {
7871  Utilities->CallLogPop(522);
7872 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7873  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7874  }
7875  else
7876  {
7877  Utilities->CallLogPop(1537);
7878  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7879  }
7880 }
7881 
7882 // ---------------------------------------------------------------------------
7883 
7885 {
7886  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7887  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7888  {
7889  TrackElementAt(1351, x).TrainIDOnElement = -1;
7892  }
7893  Utilities->CallLogPop(1342);
7894 }
7895 
7896 // ---------------------------------------------------------------------------
7897 
7898 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7899 /*
7900  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7901 */
7902 {
7903  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7904  AnsiString(ScreenPosV));
7905  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7906  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7907 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7908  Utilities->CallLogPop(535);
7909 }
7910 
7911 // ---------------------------------------------------------------------------
7912 
7913 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7914 /*
7915  Converts the screen position to the true (without offsets) position
7916 */
7917 {
7918  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7919  AnsiString(ScreenPosV));
7920  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7921  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7922  Utilities->CallLogPop(536);
7923 }
7924 
7925 // ---------------------------------------------------------------------------
7926 
7927 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7928 {
7929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7930  AnsiString(VPosTrue));
7931  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7932  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7933  Utilities->CallLogPop(537);
7934 }
7935 
7936 // ---------------------------------------------------------------------------
7937 
7938 void TTrack::CheckMapAndTrack(int Caller) // test
7939 {
7940  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7941  int Zeroes = 0;
7942  bool FoundFlag;
7943 
7944  for(unsigned int a = 0; a < TrackVector.size(); a++)
7945  {
7946  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7947  if(CheckElement.SpeedTag == 0)
7948  {
7949  Zeroes++; // zeroed elements not saved in map
7950  }
7951  else
7952  {
7953  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7954  if(!FoundFlag)
7955  {
7956  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7957  " in TrackMap, Caller=" + (AnsiString)Caller);
7958  }
7959  if(MapVecPos != (int)a)
7960  {
7961  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7962  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7963  (AnsiString)Caller);
7964  }
7965  }
7966  }
7967  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7968  {
7969  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7970  " Caller=" + (AnsiString)Caller);
7971  }
7972  Utilities->CallLogPop(538);
7973  return;
7974 }
7975 
7976 // ---------------------------------------------------------------------------
7977 
7978 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7979 {
7980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7981  bool FoundFlag;
7982  TIMPair InactivePair;
7983 
7984  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7985  {
7986  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7987  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7988  if(!FoundFlag)
7989  {
7990  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7991  " in InactiveMap, Caller=" + (AnsiString)Caller);
7992  }
7993  if((InactivePair.first != a) && (InactivePair.second != a))
7994  {
7995  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7996  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7997  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7998  }
7999  }
8000  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
8001  {
8002  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
8003  " Caller=" + (AnsiString)Caller);
8004  }
8005  Utilities->CallLogPop(539);
8006 }
8007 
8008 // ---------------------------------------------------------------------------
8009 
8010 void TTrack::CheckGapMap(int Caller) // test
8011 {
8012  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
8013  int Position1, Position2;
8014  TTrackElement TrackElement1, TrackElement2;
8015  TGapMapIterator GapMapPtr;
8016 
8017  if(!GapMap.empty())
8018  {
8019  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
8020  {
8021  int HLoc1 = GapMapPtr->first.first;
8022  int VLoc1 = GapMapPtr->first.second;
8023  int HLoc2 = GapMapPtr->second.first;
8024  int VLoc2 = GapMapPtr->second.second;
8025  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
8026  {
8027  throw Exception("Failed to find H & V for gap1, GapMap in error");
8028  }
8029  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
8030  {
8031  throw Exception("Failed to find H & V for gap2, GapMap in error");
8032  }
8033  if(TrackElementAt(17, Position1).TrackType != GapJump)
8034  {
8035  throw Exception("Element at Pos1 not a gap, GapMap in error");
8036  }
8037  if(TrackElementAt(18, Position2).TrackType != GapJump)
8038  {
8039  throw Exception("Element at Pos2 not a gap, GapMap in error");
8040  }
8041  }
8042  }
8043  unsigned int GapCount = 0;
8044 
8045  for(unsigned int a = 0; a < TrackVector.size(); a++)
8046  {
8047  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
8048  if(CheckElement.TrackType == GapJump)
8049  {
8050  GapCount++;
8051  }
8052  }
8053  if((GapMap.size() * 2) != GapCount)
8054  {
8055  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
8056  (AnsiString)Caller);
8057  }
8058  Utilities->CallLogPop(540);
8059 }
8060 
8061 // ---------------------------------------------------------------------------
8062 
8063 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
8064 {
8065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
8066  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
8067  {
8068  if(TrackFinished)
8069  {
8070  throw Exception("Error - TrackFinished with erase element still present");
8071  }
8072  Utilities->CallLogPop(541);
8073  return; // erased element, can't set ID
8074  }
8075  AnsiString IDString;
8076 
8077  if(TrackElement.HLoc < 0)
8078  {
8079  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
8080  }
8081  else
8082  {
8083  IDString = AnsiString(TrackElement.HLoc) + "-";
8084  }
8085  if(TrackElement.VLoc < 0)
8086  {
8087  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
8088  }
8089  else
8090  {
8091  IDString += AnsiString(TrackElement.VLoc);
8092  }
8093  TrackElement.ElementID = IDString;
8094  Utilities->CallLogPop(542);
8095 }
8096 
8097 // ---------------------------------------------------------------------------
8098 
8099 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
8100 {
8101 // e.g. "8-13", "00008-13", "N43-N127", etc
8102  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
8103  int DelimPos;
8104 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
8105  {
8106  for(int x = 1; x < String.Length() + 1; x++)
8107  {
8108  if(String.IsDelimiter("-", x))
8109  {
8110  DelimPos = x;
8111  break;
8112  }
8113  if(x == String.Length())
8114  {
8115  if(GiveMessages)
8116  {
8117  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8118  }
8119  Utilities->CallLogPop(543);
8120  return(-1);
8121  }
8122  }
8123  if(DelimPos == 1)
8124  {
8125  if(GiveMessages)
8126  {
8127  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8128  }
8129  Utilities->CallLogPop(544);
8130  return(-1);
8131  }
8132  if(DelimPos == String.Length())
8133  {
8134  if(GiveMessages)
8135  {
8136  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8137  }
8138  Utilities->CallLogPop(545);
8139  return(-1);
8140  }
8141  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8142  {
8143  if(GiveMessages)
8144  {
8145  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8146  }
8147  Utilities->CallLogPop(1508);
8148  return(-1);
8149  }
8150  int HLoc, VLoc;
8151 
8152  if(String.SubString(1, 1) != "N")
8153  {
8154  for(int x = 1; x < DelimPos; x++)
8155  {
8156  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8157  {
8158  if(GiveMessages)
8159  {
8160  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8161  }
8162  Utilities->CallLogPop(546);
8163  return(-1);
8164  }
8165  }
8166  }
8167  if(String.SubString(1, 1) == "N")
8168  {
8169  for(int x = 2; x < DelimPos; x++)
8170  {
8171  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8172  {
8173  if(GiveMessages)
8174  {
8175  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8176  }
8177  Utilities->CallLogPop(763);
8178  return(-1);
8179  }
8180  }
8181  }
8182  if(String.SubString(1, 1) == "N")
8183  {
8184  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8185  }
8186  else
8187  {
8188  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8189  }
8190  if(String.SubString(DelimPos + 1, 1) != "N")
8191  {
8192  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8193  {
8194  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8195  {
8196  if(GiveMessages)
8197  {
8198  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8199  }
8200  Utilities->CallLogPop(547);
8201  return(-1);
8202  }
8203  }
8204  }
8205  if(String.SubString(DelimPos + 1, 1) == "N")
8206  {
8207  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8208  {
8209  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8210  {
8211  if(GiveMessages)
8212  {
8213  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8214  }
8215  Utilities->CallLogPop(764);
8216  return(-1);
8217  }
8218  }
8219  }
8220  if(String.SubString(DelimPos + 1, 1) == "N")
8221  {
8222  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8223  }
8224  else
8225  {
8226  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8227  }
8228  THVPair HVPair(HLoc, VLoc);
8229  TTrackMapIterator TrackMapPtr;
8230 
8231  TrackMapPtr = TrackMap.find(HVPair);
8232  if(TrackMapPtr == TrackMap.end())
8233  {
8234  if(GiveMessages)
8235  {
8236  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8237  }
8238  Utilities->CallLogPop(548);
8239  return(-1);
8240  }
8241  Utilities->CallLogPop(549);
8242  return(TrackMapPtr->second);
8243  }
8244  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8245  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8246  {
8247  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8248  Utilities->CallLogPop(2481);
8249  return(-1);
8250  }
8251 }
8252 
8253 // ---------------------------------------------------------------------------
8254 
8255 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8256 /*
8257  True for linked properly at both ends
8258 */
8259 {
8260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8261  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8262  int HLoc = TrackElement.HLoc;
8263  int VLoc = TrackElement.VLoc;
8264 
8265  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8266  {
8267  Utilities->CallLogPop(1821);
8268  return(false);
8269  }
8270  if(TrackElement.SpeedTag == 129) // vertical footbridge
8271  {
8272  // check top connection
8273  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8274  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8275  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8276  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8277  {
8278  Utilities->CallLogPop(550);
8279  return(false);
8280  }
8281  // check bottom connection
8282  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8283  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8284  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8285  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8286  {
8287  Utilities->CallLogPop(551);
8288  return(false);
8289  }
8290  }
8291  if(TrackElement.SpeedTag == 145) // vertical underpass
8292  {
8293  // check top connection
8294  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8295  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8296  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8297  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8298  {
8299  Utilities->CallLogPop(2114);
8300  return(false);
8301  }
8302  // check bottom connection
8303  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8304  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8305  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8306  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8307  {
8308  Utilities->CallLogPop(2115);
8309  return(false);
8310  }
8311  }
8312  if(TrackElement.SpeedTag == 130) // hor footbridge
8313  {
8314  // check left connection
8315  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8316  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8317  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8318  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8319  {
8320  Utilities->CallLogPop(552);
8321  return(false);
8322  }
8323  // check right connection
8324  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8325  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8326  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8327  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8328  {
8329  Utilities->CallLogPop(553);
8330  return(false);
8331  }
8332  }
8333  if(TrackElement.SpeedTag == 146) // hor u'pass
8334  {
8335  // check left connection
8336  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8337  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8338  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8339  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8340  {
8341  Utilities->CallLogPop(2116);
8342  return(false);
8343  }
8344  // check right connection
8345  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8346  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8347  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8348  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8349  {
8350  Utilities->CallLogPop(2117);
8351  return(false);
8352  }
8353  }
8354  Utilities->CallLogPop(554);
8355  return(true);
8356 }
8357 
8358 // ---------------------------------------------------------------------------
8359 
8360 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8361 /*
8362  return true if the SpeedTag present in the map at H & V
8363 */
8364 {
8365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8366  AnsiString(SpeedTag));
8367  if(InactiveTrack2MultiMap.empty())
8368  {
8369  Utilities->CallLogPop(555);
8370  return(false);
8371  }
8372  THVPair HVPair(HLoc, VLoc);
8374  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8375  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8376 
8377  if(HVRange.first == HVRange.second)
8378  {
8379  Utilities->CallLogPop(556);
8380  return(false);
8381  }
8382  else
8383  {
8384  HVIt1 = HVRange.first;
8385  }
8386  TTrackElement Temp1, Temp2; // test
8387 
8388  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8389  if(--HVRange.second != HVRange.first)
8390  {
8391  HVIt2 = HVRange.second;
8392  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8393  }
8394  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8395  HVIt2->second).SpeedTag == SpeedTag)))
8396  {
8397  Utilities->CallLogPop(557);
8398  return(true);
8399  }
8400  else
8401  {
8402  Utilities->CallLogPop(558);
8403  return(false);
8404  }
8405 }
8406 
8407 // ---------------------------------------------------------------------------
8408 
8409 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8410 /*
8411  return true if the SpeedTag present in the map at H & V
8412 */
8413 {
8414  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8415  AnsiString(SpeedTag));
8416  if(TrackMap.empty())
8417  {
8418  Utilities->CallLogPop(559);
8419  return(false);
8420  }
8421  THVPair HVPair(HLoc, VLoc);
8422  TTrackMapIterator End = TrackMap.end();
8423  TTrackMapIterator It = End;
8424 
8425  It = TrackMap.find(HVPair);
8426  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8427  {
8428  Utilities->CallLogPop(560);
8429  return(true);
8430  }
8431  else
8432  {
8433  Utilities->CallLogPop(561);
8434  return(false);
8435  }
8436 }
8437 
8438 // ---------------------------------------------------------------------------
8439 
8440 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8441 {
8442 /*
8443  General:
8444  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8445  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8446  a NamedNonStationLocation.
8447  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8448  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8449  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8450  platform at that location).
8451 
8452  Linked named location elements are those explained in TTrack::TTrack()
8453 
8454  Detail:
8455  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8456  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8457  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8458  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8459  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8460  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8461 
8462  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8463  this function a single element should be in the List (normally from the user's selection but can also be from
8464  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8465  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8466  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8467  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8468  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8469  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8470  moves them into the Map. At the end all linked elements are in the Map.
8471 
8472  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8473  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8474  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8475 */
8476 
8477 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8478 // Display->FileDiagnostics(TestString);//test
8479 
8480  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8481  AnsiString TestString1, TestString2; // test
8482 
8483  Track->LNDone2MultiMap.clear();
8484  if(LNPendingList.size() != 1)
8485  {
8486  throw Exception("LNPendingList size not 1 on entry");
8487  }
8488  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8489  bool FoundFlag = false, ErasedFlag = false;
8490  while(!LNPendingList.empty())
8491  {
8492  CurrentElementNumber = LNPendingList.front();
8493  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8494  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8495  int H = CurrentElement->HLoc;
8496  int V = CurrentElement->VLoc;
8497  int Tag = CurrentElement->SpeedTag;
8498  if(Tag == 76) // top plat
8499  {
8500  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8501  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8502  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8503  for(int x = 0; x < 25; x++)
8504  {
8505  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8506  {
8507  LNPendingList.insert(LNPendingList.end(), NewElement);
8508  }
8509  }
8510  }
8511  else if(Tag == 77) // bot plat
8512  {
8513  for(int x = 0; x < 25; x++)
8514  {
8515  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8516  {
8517  LNPendingList.insert(LNPendingList.end(), NewElement);
8518  }
8519  }
8520  }
8521  else if(Tag == 78) // l plat
8522  {
8523  for(int x = 0; x < 25; x++)
8524  {
8525  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8526  {
8527  LNPendingList.insert(LNPendingList.end(), NewElement);
8528  }
8529  }
8530  }
8531  else if(Tag == 79) // r plat
8532  {
8533  for(int x = 0; x < 25; x++)
8534  {
8535  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8536  {
8537  LNPendingList.insert(LNPendingList.end(), NewElement);
8538  }
8539  }
8540  }
8541  else if(Tag == 96) // conc
8542  {
8543  for(int x = 0; x < 28; x++)
8544  {
8545  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8546  {
8547  LNPendingList.insert(LNPendingList.end(), NewElement);
8548  }
8549  }
8550  }
8551  else if(Tag == 129) // vert footbridge
8552  {
8553  for(int x = 0; x < 8; x++)
8554  {
8555  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8556  {
8557  LNPendingList.insert(LNPendingList.end(), NewElement);
8558  }
8559  }
8560  }
8561  else if(Tag == 130) // hor footbridge
8562  {
8563  for(int x = 0; x < 8; x++)
8564  {
8565  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8566  {
8567  LNPendingList.insert(LNPendingList.end(), NewElement);
8568  }
8569  }
8570  }
8571  else if(Tag == 131) // named location
8572  {
8573  for(int x = 0; x < 4; x++)
8574  {
8575  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8576  {
8577  LNPendingList.insert(LNPendingList.end(), NewElement);
8578  }
8579  }
8580  int TVPos = GetVectorPositionFromTrackMap(67, H, V, FoundFlag); //deal with gaps, added at v2.18.0
8581  {
8582  if(FoundFlag && TrackElementAt(1585, TVPos).TrackType == GapJump)
8583  {
8584  int GJTVPos = TrackElementAt(1586, TVPos).Conn[0];
8585  if(GJTVPos > -1)
8586  {
8587  int HLoc = TrackElementAt(1587, GJTVPos).HLoc;
8588  int VLoc = TrackElementAt(1588, GJTVPos).VLoc;
8589  bool FoundFlag2 = false;
8590  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(33, HLoc, VLoc, FoundFlag2);
8591  if(FoundFlag2)
8592  {
8593  if(Track->InactiveTrackElementAt(1410, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
8594  {
8595  if(!ElementInLNDone2MultiMap(5, IMPair.first) && !ElementInLNPendingList(6, IMPair.first))
8596  {
8597  LNPendingList.insert(LNPendingList.end(), IMPair.first);
8598  }
8599  }
8600  }
8601  }
8602  }
8603  }
8604  }
8605  else if(Tag == 145) // v u'pass
8606  {
8607  for(int x = 0; x < 8; x++)
8608  {
8609  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8610  {
8611  LNPendingList.insert(LNPendingList.end(), NewElement);
8612  }
8613  }
8614  }
8615  else if(Tag == 146) // h u'pass
8616  {
8617  for(int x = 0; x < 8; x++)
8618  {
8619  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8620  {
8621  LNPendingList.insert(LNPendingList.end(), NewElement);
8622  }
8623  }
8624  }
8625  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8626 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8627  if(AddingElements)
8628  {
8629  int HPos, VPos; // not used but needed for FindText function
8630  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8631  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8632  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8633  {
8634  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8635  if((ExistingName != "") && (ExistingName != LocationName))
8636  {
8637  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8638  {
8639  } // name not in LocationNameMultiMap, so don't erase from TextVector
8640  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8641  {
8642  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8643  {
8644  ;
8645  } // condition not used
8646 
8647  }
8648  }
8649  }
8650  }
8651  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8652  // track at that loc
8653  THVPair HVPair(H, V);
8654  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8655  LNDone2MultiMapEntry.first = HVPair;
8656  LNDone2MultiMapEntry.second = LNPendingList.front();
8657  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8658  LNPendingList.erase(LNPendingList.begin());
8659  }
8660 
8661 // search all name multimap for same name where corresponding active elements don't appear in
8662 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8663 
8664  TLocationNameMultiMapIterator SNIterator;
8665  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8666 
8667  if(SNRange.first != SNRange.second)
8668  {
8669  SNRange.first--; // now pointing to before the first
8670  SNRange.second--; // now pointing to the last
8671  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8672  {
8673  // Same elements are in Done map as in name map
8674  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8675  {
8676  ErasedFlag = true;
8677  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8678  TVIt->LocationName = "";
8679  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8680  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8681  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8682  {
8683  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8684  if(FoundFlag)
8685  {
8686  TrackElementAt(20, Position).LocationName = "";
8687  TrackElementAt(21, Position).ActiveTrackElementName = "";
8688  }
8689  }
8690  // erase name in name map
8691 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8692  }
8693  }
8694  }
8695  if(ErasedFlag)
8696  {
8698  }
8699  if(TrackFinished)
8700  {
8703  }
8704 // set here as well as in LinkTrack so don't have to link track just because a name added
8705 // if track not finished then will be set when track validated
8706 
8707 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8708 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8709 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8710 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8711 // so the error would be seen.
8712 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8713  std::pair<AnsiString, char>TempMapPair;
8714 
8715  ContinuationNameMap.clear();
8716  for(int x = 0; x < Track->TrackVectorSize(); x++)
8717  {
8718  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8719  {
8720  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8721  TempMapPair.second = 'x'; // unused
8722  ContinuationNameMap.insert(TempMapPair);
8723  }
8724  }
8725 //end of addition
8726  CheckLocationNameMultiMap(1); // test
8727  Utilities->CallLogPop(562);
8728 }
8729 
8730 // ---------------------------------------------------------------------------
8731 
8732 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8733 /*
8734  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8735  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8736 */
8737 {
8738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8739  AnsiString(SpeedTag));
8740  if(!NamedLocationElementAt(2, HLoc, VLoc))
8741  {
8742  Utilities->CallLogPop(948);
8743  return(false);
8744  }
8745  bool FoundFlag;
8746  int Position = -1;
8747  TIMPair IMPair;
8748 
8749  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8750  {
8751  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8752  if(FoundFlag)
8753  {
8754  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8755  {
8756  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8757  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8758  // don't allow duplicates in either list, or processing takes a lot longer
8759  {
8760  FoundElement = MapPos;
8761  Utilities->CallLogPop(563);
8762  return(true);
8763  }
8764  }
8765  }
8766  }
8767  else
8768  {
8769  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8770  if(FoundFlag)
8771  {
8772  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8773  {
8774  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8775  {
8776  FoundElement = IMPair.first;
8777  Utilities->CallLogPop(564);
8778  return(true);
8779  }
8780  }
8781  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8782  {
8783  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8784  {
8785  FoundElement = IMPair.second;
8786  Utilities->CallLogPop(565);
8787  return(true);
8788  }
8789  }
8790  }
8791  }
8792  Utilities->CallLogPop(566);
8793  return(false);
8794 }
8795 
8796 // ---------------------------------------------------------------------------
8797 
8798 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8799 /*
8800  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8801  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8802  with the new name
8803 */
8804 {
8805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8806  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8807 
8808  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8809  int HLoc = TrackElement->HLoc;
8810  int VLoc = TrackElement->VLoc;
8811  bool FoundFlag;
8812 
8813  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8814  // only have timetable names for adjacent platforms & named locations
8815  {
8816  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8817  if(FoundFlag)
8818  {
8819  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8820  }
8821  }
8822  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8823 
8824  if(ErrorString != "")
8825  {
8826  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8827  }
8828  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8829  CheckLocationNameMultiMap(2); // test
8830  Utilities->CallLogPop(567);
8831 }
8832 
8833 // ---------------------------------------------------------------------------
8834 
8835 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8836 /*
8837  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8838 */
8839 {
8840  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8841  if(LNDone2MultiMap.empty())
8842  {
8843  Utilities->CallLogPop(568);
8844  return(false);
8845  }
8846  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8847 
8848  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8849  {
8850  if(LNDone2MultiMapIterator->second == MapPos)
8851  {
8852  Utilities->CallLogPop(569);
8853  return(true);
8854  }
8855  }
8856  Utilities->CallLogPop(570);
8857  return(false);
8858 }
8859 
8860 // ---------------------------------------------------------------------------
8861 
8862 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8863 /*
8864  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8865 */
8866 {
8867  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8868  if(LNPendingList.empty())
8869  {
8870  Utilities->CallLogPop(571);
8871  return(false);
8872  }
8873  TLNPendingListIterator LNPendingListIterator;
8874 
8875  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8876  {
8877  if(*LNPendingListIterator == MapPos)
8878  {
8879  Utilities->CallLogPop(572);
8880  return(true);
8881  }
8882  }
8883  Utilities->CallLogPop(573);
8884  return(false);
8885 }
8886 
8887 // ---------------------------------------------------------------------------
8888 
8889 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8890 /*
8891  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8892 */
8893 {
8894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8895  THVPair HVPair(HLoc, VLoc);
8896  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8897  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8898 
8899  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8900  {
8901  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8902  {
8903  Utilities->CallLogPop(574);
8904  return(true);
8905  }
8906  }
8907  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8908  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8909  {
8910  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8911  {
8912  Utilities->CallLogPop(575);
8913  return(true);
8914  }
8915  }
8916  Utilities->CallLogPop(576);
8917  return(false);
8918 }
8919 
8920 // ---------------------------------------------------------------------------
8921 
8922 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8923 {
8924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8925  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8926  {
8927  Utilities->CallLogPop(1953);
8928  return(true);
8929  }
8930  Utilities->CallLogPop(1954);
8931  return(false);
8932 }
8933 
8934 // ---------------------------------------------------------------------------
8935 
8936 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8937 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8938 //program and used when try to save as a .rly file
8939 {
8940  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8943  if(LocationNameMultiMap.empty()) //no names so no duplicates
8944  {
8945  Utilities->CallLogPop(2254);
8946  return(false);
8947  }
8948  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8949  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8950  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8951  {
8953  {
8954  if(GiveMessage)
8955  {
8956  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8957  }
8958  Utilities->CallLogPop(2255);
8959  return(true);
8960  }
8961  }
8962  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8963  {
8964  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8965  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8966  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8967  {
8969  {
8970  if(GiveMessage)
8971  {
8972  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8973  }
8974  Utilities->CallLogPop(2256);
8975  return(true);
8976  }
8977  }
8978  }
8979  Utilities->CallLogPop(2257);
8980  return(false); //OK, no duplicates
8981 }
8982 
8983 // ---------------------------------------------------------------------------
8984 
8986 {
8987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8988  THVPair HVPair;
8989  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8990  //for use in the duplicate check
8991  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8992  {
8993  if(LNMMIt->second < 0) //active track element
8994  {
8995  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8996  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8997  }
8998  else //inactive track element
8999  {
9000  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
9001  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
9002  }
9003  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
9004  }
9005  //All HVPairs now present in HVPairsLinkedMap for the specific location name
9006 
9007  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
9008  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
9009  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
9010 
9011  std::list<THVPair> HVLinkedList;
9012 
9013  //set the first value to true and add it to the list
9014  HVPairsLinkedMap.begin()->second = true;
9015  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
9016  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
9017  //examination
9018  THVPair HVPairUnderExamination;
9019  THVPairsLinkedMap::iterator HVPLMIt;
9020  THVPair HVPairNew;
9021  while(!HVLinkedList.empty())
9022  {
9023  HVPairUnderExamination = HVLinkedList.front();
9024  HVLinkedList.pop_front();
9025  HVPairNew.first = HVPairUnderExamination.first;
9026  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
9027  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9028  if(HVPLMIt != HVPairsLinkedMap.end())
9029  {
9030  if(!HVPLMIt->second)
9031  {
9032  HVLinkedList.push_back(HVPLMIt->first);
9033  }
9034  HVPLMIt->second = true;
9035  }
9036  HVPairNew.first = HVPairUnderExamination.first - 1;
9037  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
9038  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9039  if(HVPLMIt != HVPairsLinkedMap.end())
9040  {
9041  if(!HVPLMIt->second)
9042  {
9043  HVLinkedList.push_back(HVPLMIt->first);
9044  }
9045  HVPLMIt->second = true;
9046  }
9047  HVPairNew.first = HVPairUnderExamination.first;
9048  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
9049  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9050  if(HVPLMIt != HVPairsLinkedMap.end())
9051  {
9052  if(!HVPLMIt->second)
9053  {
9054  HVLinkedList.push_back(HVPLMIt->first);
9055  }
9056  HVPLMIt->second = true;
9057  }
9058  HVPairNew.first = HVPairUnderExamination.first + 1;
9059  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
9060  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9061  if(HVPLMIt != HVPairsLinkedMap.end())
9062  {
9063  if(!HVPLMIt->second)
9064  {
9065  HVLinkedList.push_back(HVPLMIt->first);
9066  }
9067  HVPLMIt->second = true;
9068  }
9069  }
9070 
9071  //at the end if any have a false bool then the name is duplicated so return false
9072  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
9073  {
9074  if(!HVPLMIt->second)
9075  {
9076  Utilities->CallLogPop(2258);
9077  return(false);
9078  }
9079  }
9080  Utilities->CallLogPop(2259);
9081  return(true);
9082 }
9083 
9084 // ---------------------------------------------------------------------------
9085 
9086 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
9087 /*
9088  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
9089 */
9090 
9091 {
9092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
9093  if(LocationName == "")
9094  {
9095  Utilities->CallLogPop(577);
9096  return(false);
9097  }
9098 // new for v0.2b
9099 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
9101  {
9102  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
9103  ActiveTrackElementNameMap.clear();
9104  for(unsigned int x = 0; x < TrackVector.size(); x++)
9105  {
9106  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
9107  == ContinuationNameMap.end())
9108  {
9109  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
9110  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
9111  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
9112  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
9113  }
9114  }
9116  }
9117  Utilities->CallLogPop(578);
9118  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
9119 // end of new section
9120 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
9121 }
9122 
9123 // ---------------------------------------------------------------------------
9124 
9125 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
9126 /*
9127  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
9128  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
9129  new names in the vectors.
9130 */
9131 {
9132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
9133  bool FoundFlag, ErasedFlag = false;
9134  TLocationNameMultiMapIterator SNIterator;
9135  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9136 
9137  if(SNRange.first != SNRange.second)
9138  {
9139  ErasedFlag = true;
9140  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9141  {
9142  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9143  TVIt->LocationName = "";
9144  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9145  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9146  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9147  {
9148  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9149  if(FoundFlag)
9150  {
9151  TrackElementAt(25, Position).LocationName = "";
9152  TrackElementAt(26, Position).ActiveTrackElementName = "";
9153  }
9154  }
9155  }
9156  }
9157  if(ErasedFlag)
9158  {
9160  }
9161  CheckLocationNameMultiMap(3); // test
9162  Utilities->CallLogPop(579);
9163 }
9164 
9165 // ---------------------------------------------------------------------------
9166 
9167 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9168 /*
9169  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9170  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9171  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9172  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during PlotAndAddTrackElement,
9173  to bring the named location and timetable naming up to date with the deletion or insertion. Note that only one name is sought,
9174  it is entered into LNPendingList and EnterLocationName sets all others.
9175 */
9176 {
9177  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9178  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9179  LNPendingList.clear();
9180  AnsiString LocationName;
9181  int MapPos;
9182  bool FoundFlag = 0;
9183 
9184 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9185  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9186  if(FoundFlag)
9187  {
9188  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9189  if(LocationName != "")
9190  {
9191  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9192  EnterLocationName(13, LocationName, true);
9193  Utilities->CallLogPop(2251);
9194  return;
9195  }
9196  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9197  if(LocationName != "")
9198  {
9199  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9200  EnterLocationName(14, LocationName, true);
9201  Utilities->CallLogPop(2252);
9202  return;
9203  }
9204  }
9205 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9206 
9207  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9208  if(FoundFlag)
9209  {
9210  LocationName = TrackElementAt(1004, Position).LocationName;
9211  if(LocationName != "")
9212  {
9213  int ModifiedPosition = -1 - Position;
9214  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9215  EnterLocationName(15, LocationName, true);
9216  Utilities->CallLogPop(2253);
9217  return;
9218  }
9219  }
9220  if(SpeedTag == 76) // top plat
9221  {
9222  for(int x = 0; x < 25; x++)
9223  {
9224  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9225  {
9226  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9227  EnterLocationName(3, LocationName, true);
9228  break;
9229  }
9230  }
9231  }
9232  else if(SpeedTag == 77) // bot plat
9233  {
9234  for(int x = 0; x < 25; x++)
9235  {
9236  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9237  {
9238  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9239  EnterLocationName(4, LocationName, true);
9240  break;
9241  }
9242  }
9243  }
9244  else if(SpeedTag == 78) // l plat
9245  {
9246  for(int x = 0; x < 25; x++)
9247  {
9248  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9249  {
9250  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9251  EnterLocationName(5, LocationName, true);
9252  break;
9253  }
9254  }
9255  }
9256  else if(SpeedTag == 79) // r plat
9257  {
9258  for(int x = 0; x < 25; x++)
9259  {
9260  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9261  {
9262  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9263  EnterLocationName(6, LocationName, true);
9264  break;
9265  }
9266  }
9267  }
9268  else if(SpeedTag == 96) // conc
9269  {
9270  for(int x = 0; x < 28; x++)
9271  {
9272  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9273  {
9274  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9275  EnterLocationName(7, LocationName, true);
9276  break;
9277  }
9278  }
9279  }
9280  else if(SpeedTag == 129) // vert footbridge
9281  {
9282  for(int x = 0; x < 8; x++)
9283  {
9284  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9285  {
9286  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9287  EnterLocationName(8, LocationName, true);
9288  break;
9289  }
9290  }
9291  }
9292  else if(SpeedTag == 130) // hor footbridge
9293  {
9294  for(int x = 0; x < 8; x++)
9295  {
9296  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9297  {
9298  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9299  EnterLocationName(9, LocationName, true);
9300  break;
9301  }
9302  }
9303  }
9304  else if(SpeedTag == 145) // vert u'pass
9305  {
9306  for(int x = 0; x < 8; x++)
9307  {
9308  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9309  {
9310  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9311  EnterLocationName(11, LocationName, true);
9312  break;
9313  }
9314  }
9315  }
9316  else if(SpeedTag == 146) // hor u'pass
9317  {
9318  for(int x = 0; x < 8; x++)
9319  {
9320  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9321  {
9322  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9323  EnterLocationName(12, LocationName, true);
9324  break;
9325  }
9326  }
9327  }
9328  else if(SpeedTag == 131) // named location
9329  {
9330  for(int x = 0; x < 4; x++)
9331  {
9332  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9333  {
9334  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9335  EnterLocationName(10, LocationName, true);
9336  Utilities->CallLogPop(2657);
9337  return;
9338  }
9339  }
9340  int TVPos = GetVectorPositionFromTrackMap(68, HLoc, VLoc, FoundFlag); //deal with gaps, added at v2.18.0
9341  {
9342  if(FoundFlag && TrackElementAt(1589, TVPos).TrackType == GapJump)
9343  {
9344  int GJTVPos = TrackElementAt(1590, TVPos).Conn[0];
9345  if(GJTVPos > -1)
9346  {
9347  int HLoc2 = TrackElementAt(1591, GJTVPos).HLoc;
9348  int VLoc2 = TrackElementAt(1592, GJTVPos).VLoc;
9349  LocationName = TrackElementAt(1593, GJTVPos).ActiveTrackElementName;
9350  bool FoundFlag2 = false;
9351  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(34, HLoc2, VLoc2, FoundFlag2);
9352  if(FoundFlag2)
9353  {
9354  if(Track->InactiveTrackElementAt(1411, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
9355  {
9356  LNPendingList.insert(LNPendingList.end(), IMPair.first);
9357  EnterLocationName(16, LocationName, true);
9358  }
9359  }
9360  }
9361  }
9362  }
9363  }
9364 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9365  Utilities->CallLogPop(580);
9366 }
9367 
9368 // ---------------------------------------------------------------------------
9369 
9370 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9371 /*
9372  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9373  true if a LocationName is found, and also returns the name and the adjusted vector position.
9374 */
9375 {
9376  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9377  AnsiString(SpeedTag));
9378  bool FoundFlag;
9379  TIMPair IMPair;
9380  TTrackVectorIterator TempElement;
9381  int Position;
9382 
9383  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9384  if(FoundFlag)
9385  {
9386  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9387  {
9388  TempElement = InactiveTrackVector.begin() + IMPair.first;
9389  if(TempElement->LocationName != "")
9390  {
9391  LocationName = TempElement->LocationName;
9392  FoundElement = IMPair.first;
9393  Utilities->CallLogPop(581);
9394  return(true);
9395  }
9396  }
9397  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9398  {
9399  TempElement = InactiveTrackVector.begin() + IMPair.second;
9400  if(TempElement->LocationName != "")
9401  {
9402  LocationName = TempElement->LocationName;
9403  FoundElement = IMPair.second;
9404  Utilities->CallLogPop(582);
9405  return(true);
9406  }
9407  }
9408  }
9409  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9410  if(FoundFlag)
9411  {
9412  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9413  {
9414  TempElement = TrackVector.begin() + Position;
9415  if(TempElement->LocationName != "")
9416  {
9417  LocationName = TempElement->LocationName;
9418  FoundElement = -1 - Position;
9419  Utilities->CallLogPop(583);
9420  return(true);
9421  }
9422  }
9423  }
9424  Utilities->CallLogPop(584);
9425  return(false);
9426 }
9427 
9428 // ---------------------------------------------------------------------------
9429 
9430 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9431 {
9432 // check quantity in map & vectors match
9433  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9434  unsigned int Count = 0;
9435 
9436  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9437  {
9438  Utilities->CallLogPop(2059);
9439  return;
9440  }
9441  AnsiString SName, TName, ErrorString;
9442 
9443  for(unsigned int x = 0; x < TrackVector.size(); x++)
9444  {
9445  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9446  {
9447  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9448  {
9449  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9450  AnsiString(Caller));
9451  }
9452  Count++;
9453  }
9454  }
9455  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9456  {
9457  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9458  {
9459  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9460  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9461  {
9462  throw Exception
9463  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9464  AnsiString(Caller));
9465  }
9466  Count++;
9467  }
9468  }
9469  if(LocationNameMultiMap.size() != Count)
9470  {
9471  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9472  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9473  }
9474 // check all entries in both vectors match entries in name multimap
9476 
9477  for(unsigned int x = 0; x < TrackVector.size(); x++)
9478  {
9479  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9480  {
9481  SName = TrackElementAt(1365, x).LocationName;
9482  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9483  if(ErrorString != "")
9484  {
9485  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9486  }
9487  if(SNIt->second != -1 - (int)x)
9488  {
9489  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9490  AnsiString(Caller));
9491  }
9492  }
9493  // check corresponding platform for all Timetable entries that aren't empty
9494  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9495  TIMPair IMPair;
9496  bool FoundFlag = false;
9497  if(TName != "")
9498  {
9499  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9500  if(FoundFlag)
9501  {
9502  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9504  {
9505  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9506  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9507  }
9508  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9509  {
9510  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9511  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9512  AnsiString(Caller));
9513  }
9514  }
9515  else
9516  {
9517  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9518  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9519  }
9520  }
9521  }
9522  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9523  {
9524  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9525  {
9526  SName = InactiveTrackElementAt(148, x).LocationName;
9527  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9528  if(ErrorString != "")
9529  {
9530  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9531  }
9532  if(SNIt->second != (int)x)
9533  {
9534  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9535  AnsiString(Caller));
9536  }
9537  }
9538  }
9539  Utilities->CallLogPop(585);
9540 }
9541 
9542 // ---------------------------------------------------------------------------
9543 
9545  AnsiString &ErrorString)
9546 {
9547 /*
9548  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9549  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9550  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9551 */
9552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9553  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9554  ErrorString = "";
9555  bool FoundFlag = false;
9556  TLocationNameMultiMapIterator SNIterator;
9557  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9558 
9559  if(SNRange.first == SNRange.second)
9560  {
9561  ErrorString = "Error, Name " + LocationName + " not found in map";
9562  Utilities->CallLogPop(586);
9563  return(SNRange.first);
9564  }
9565  else
9566  {
9567  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9568  {
9569  if(SNIterator->second < 0)
9570  {
9571  int TVPos = -1 - SNIterator->second;
9572  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9573  if(TVIt == TrackElement)
9574  {
9575  FoundFlag = true;
9576  Utilities->CallLogPop(587);
9577  return(SNIterator);
9578  }
9579  }
9580  else
9581  {
9582  int ITVPos = SNIterator->second;
9583  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9584  if(ITVIt == TrackElement)
9585  {
9586  FoundFlag = true;
9587  Utilities->CallLogPop(588);
9588  return(SNIterator);
9589  }
9590  }
9591  }
9592  }
9593  if(!FoundFlag)
9594  {
9595  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9596  }
9597  Utilities->CallLogPop(589);
9598  return(SNIterator);
9599 }
9600 
9601 // ---------------------------------------------------------------------------
9602 
9603 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9604 {
9605 /*
9606  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9607  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9608 */
9609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9610  TLocationNameMultiMapEntry LocationNameEntry;
9611 
9612  LocationNameEntry.first = NewName;
9613  LocationNameEntry.second = SNIterator->second;
9614  LocationNameMultiMap.erase(SNIterator);
9615  LocationNameMultiMap.insert(LocationNameEntry);
9616  Utilities->CallLogPop(590);
9617 }
9618 
9619 // ---------------------------------------------------------------------------
9620 
9622 {
9623 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9624  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9625  if(Position < 0) // footcrossing
9626  {
9627  int TruePos = -1 - Position;
9628  // new check at v0.2b
9629  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9630  {
9631  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9632  }
9633  Utilities->CallLogPop(591);
9634  return (TrackVector.begin() + TruePos);
9635  }
9636  else
9637  {
9638  // new check at v0.2b
9639  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9640  {
9641  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9642  }
9643  Utilities->CallLogPop(592);
9644  return (InactiveTrackVector.begin() + Position);
9645  }
9646 }
9647 
9648 // ---------------------------------------------------------------------------
9649 
9650 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9651 {
9652 /*
9653  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9654  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9655  LocationNameMultiMap.
9656 */
9657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9658  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9659  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9660 
9661  if(!InactiveTrack2MultiMap.empty())
9662  {
9663  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9664  InactiveTrack2MultiMapIterator++)
9665  {
9666  if(InactiveTrack2MultiMapIterator->second > VecPos)
9667  {
9668  InactiveTrack2MultiMapIterator->second--;
9669  }
9670  // can't be == VecPos as that position erased
9671  }
9672  }
9673  if(!LocationNameMultiMap.empty())
9674  {
9675  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9676  LocationNameMultiMapIterator++)
9677  {
9678  if(LocationNameMultiMapIterator->second < 0)
9679  {
9680  continue; // deal with TrackVectors separately
9681  }
9682  if(LocationNameMultiMapIterator->second > (int)VecPos)
9683  {
9684  LocationNameMultiMapIterator->second--;
9685  }
9686  }
9687  }
9688  Utilities->CallLogPop(593);
9689 }
9690 
9691 // ---------------------------------------------------------------------------
9692 
9693 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9694 {
9695 /*
9696  After an element has been erased from the track vector, all the later elements are moved down one. This function
9697  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9698  LocationNameMultiMap.
9699 */
9700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9701  TTrackMapIterator TrackMapIterator;
9702  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9703 
9704  if(!TrackMap.empty())
9705  {
9706  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9707  {
9708  if(TrackMapIterator->second > VecPos)
9709  {
9710  TrackMapIterator->second--;
9711  }
9712  // can't be == VecPos as that position erased
9713  }
9714  }
9715  if(!LocationNameMultiMap.empty())
9716  {
9717  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9718  LocationNameMultiMapIterator++)
9719  {
9720  if(LocationNameMultiMapIterator->second >= 0)
9721  {
9722  continue; // deal with InactiveTrackVectors separately
9723  }
9724  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9725  // Val -1 -2 -3 -4 -5 -6 -7 -8
9726  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9727  {
9728  LocationNameMultiMapIterator->second++;
9729  }
9730  }
9731  }
9732  for(unsigned int x = 0; x < TrackVector.size(); x++)
9733  {
9734  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9735  if(TkEl.TrackType == GapJump)
9736  {
9737  // position 0 is the gap
9738  if(TkEl.Conn[0] == int(VecPos))
9739  {
9740  TkEl.Conn[0] = -1; // connected to a deleted gap
9741  continue;
9742  }
9743  if(TkEl.Conn[0] > int(VecPos))
9744  {
9745  TkEl.Conn[0]--;
9746  }
9747  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9748  {
9749  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9750  {
9751  TkEl.Conn[0] = -1;
9752  }
9753  }
9754  }
9755  }
9756  Utilities->CallLogPop(1433);
9757 }
9758 
9759 // ---------------------------------------------------------------------------
9760 
9762 /*
9763  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9764  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9765  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9766  InactiveTrackvector values are stored as they are, 0 to n, whereas ActiveTrackvector values stored as -1 - TVPos, i.e.
9767  running from -1 to -1 - n
9768 */
9769 {
9770  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9771  LocationNameMultiMap.clear();
9772  TLocationNameMultiMapEntry LocationNameEntry;
9773  TTrackElement TrackElement;
9774 
9775  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9776  {
9777  TrackElement = TrackElementAt(1376, TVPos);
9778  if(TrackElement.FixedNamedLocationElement)
9779  {
9780  LocationNameEntry.first = TrackElement.LocationName;
9781  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9782  LocationNameMultiMap.insert(LocationNameEntry);
9783  }
9784  }
9785 
9786  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9787  {
9788  TrackElement = InactiveTrackElementAt(149, ITVPos);
9789  if(TrackElement.FixedNamedLocationElement)
9790  {
9791  LocationNameEntry.first = TrackElement.LocationName;
9792  LocationNameEntry.second = ITVPos;
9793  LocationNameMultiMap.insert(LocationNameEntry);
9794  }
9795  }
9796  Utilities->CallLogPop(594);
9797 }
9798 
9799 // ---------------------------------------------------------------------------
9800 
9802 // Return true if there is a named location present in the railway
9803 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9804 {
9805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9806  TTrackVectorIterator ITVI;
9807 
9808  if(InactiveTrackVector.empty())
9809  {
9810  Utilities->CallLogPop(1343);
9811  return(false);
9812  }
9813  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9814  {
9815  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9816  {
9817  Utilities->CallLogPop(1404);
9818  return(true);
9819  }
9820  }
9821  Utilities->CallLogPop(1344);
9822  return(false);
9823 }
9824 
9825 // ---------------------------------------------------------------------------
9826 
9828 /*
9829  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9830 */
9831 {
9832  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9833 // ResetDistanceElements(6);
9834  for(unsigned int x = 0; x < TrackVector.size(); x++)
9835  {
9836  TTrackElement &TE = TrackElementAt(718, x);
9839  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9840  {
9843  }
9844  }
9845 /* old function
9846  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9847  {
9848  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9849  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9850  }
9851  else
9852  {
9853  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9854  }
9855  }
9856 */
9857  Utilities->CallLogPop(617);
9858 }
9859 
9860 // ---------------------------------------------------------------------------
9861 
9863 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLengthandSpeed.
9864 {
9865  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthandSpeedMarker");
9866  for(unsigned int x = 0; x < TrackVector.size(); x++)
9867  {
9868  TTrackElement TempElement = TrackElementAt(1377, x);
9869  if(TempElement.Length01 > -1)
9870  {
9871  MarkOneLengthandSpeed(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9872  }
9873  if(TempElement.Length23 > -1)
9874  {
9875  MarkOneLengthandSpeed(2, TempElement, false, Disp);
9876  }
9877  }
9878  Disp->Update();
9879  Utilities->CallLogPop(618);
9880 }
9881 
9882 // ---------------------------------------------------------------------------
9883 void TTrack::LengthOrSpeedHeatMap(int Caller, bool Length, TDisplay *Disp) //Length false -> speed heatmap //unused //added at v2.22.0
9884 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using OneLengthOrSpeedHeatMapColour
9885 {
9886  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthOrSpeedHeatMap");
9887  for(unsigned int x = 0; x < TrackVector.size(); x++)
9888  {
9889  TTrackElement TempElement = TrackElementAt(1689, x);
9890  if(((TempElement.HLoc - Display->DisplayOffsetH) >= 0) && ((TempElement.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
9891  ((TempElement.VLoc - Display->DisplayOffsetV) >= 0) && ((TempElement.VLoc - Display->DisplayOffsetV) < Utilities->ScreenElementHeight))
9892  {//only plot if onscreen as takes quite a long time
9893  if(TempElement.Length01 > -1)
9894  {
9895  OneLengthOrSpeedHeatMapColour(8, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9896  }
9897  if(TempElement.Length23 > -1)
9898  {
9899  OneLengthOrSpeedHeatMapColour(9, TempElement, false, Disp);
9900  }
9901  }
9902  }
9903  Disp->Update();
9904  Utilities->CallLogPop(2722);
9905 }
9906 
9907 // ---------------------------------------------------------------------------
9908 
9909 void TTrack::OneLengthOrSpeedHeatMapColour(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp) //added at v2.22.0
9910 
9911 {
9912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneLengthOrSpeedHeatMapColour," + TrackElement.LogTrack(8) + "," +
9913  AnsiString((short)FirstTrack));
9914 
9915  int EXArray[16][2] =
9916  {{4, 6}, {2, 8}, // horizontal & vertical
9917  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9918  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9919  {1, 9}, {3, 7}}; // forward & reverse diagonals
9920 
9921  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink; //BrNum = bridge number, GrNum = graphic number
9922  Graphics::TBitmap *Bitmap;
9923  int Length;
9924  int Speed;
9925 
9926  if(FirstTrack)
9927  {
9928  InLink = TrackElement.Link[0];
9929  OutLink = TrackElement.Link[1];
9930  Length = TrackElement.Length01;
9931  Speed = TrackElement.SpeedLimit01;
9932  }
9933  else
9934  {
9935  InLink = TrackElement.Link[2];
9936  OutLink = TrackElement.Link[3];
9937  Length = TrackElement.Length23;
9938  Speed = TrackElement.SpeedLimit23;
9939  }
9940  for(int x = 0; x < 16; x++)
9941  {
9942  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9943  {
9944  Index = x;
9945  }
9946  }
9947  if(Index == -1)
9948  {
9949  throw Exception("Error, failed to find Index in TTrack::MarkOneLengthandSpeed");
9950  }
9951 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9952  the graphic for each of which is different because of the shape of the overbridge. The basic
9953  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9954  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9955  Note that the underbridge track always uses links 2 & 3
9956  int BrEXArray[24][2] = {
9957  {4,6},{2,8},{1,9},{3,7},
9958  {1,9},{3,7},{1,9},{3,7},
9959  {2,8},{4,6},{2,8},{4,6}
9960 */
9961 
9962  if(!FirstTrack && (TrackElement.TrackType == Bridge)) //underbridge track always uses links 2 & 3 so never FirstTrack
9963  {
9964  if(Index == 1)
9965  {
9966  if(TrackElement.SpeedTag == 49)
9967  {
9968  BrNum = 1 + 16;
9969  }
9970  else if(TrackElement.SpeedTag == 54)
9971  {
9972  BrNum = 8 + 16;
9973  }
9974  else if(TrackElement.SpeedTag == 55)
9975  {
9976  BrNum = 10 + 16;
9977  }
9978  }
9979  else if(Index == 0)
9980  {
9981  if(TrackElement.SpeedTag == 48)
9982  {
9983  BrNum = 0 + 16;
9984  }
9985  else if(TrackElement.SpeedTag == 58)
9986  {
9987  BrNum = 11 + 16;
9988  }
9989  else if(TrackElement.SpeedTag == 59)
9990  {
9991  BrNum = 9 + 16;
9992  }
9993  }
9994  else if(Index == 14)
9995  {
9996  if(TrackElement.SpeedTag == 50)
9997  {
9998  BrNum = 2 + 16;
9999  }
10000  else if(TrackElement.SpeedTag == 52)
10001  {
10002  BrNum = 4 + 16;
10003  }
10004  else if(TrackElement.SpeedTag == 57)
10005  {
10006  BrNum = 6 + 16;
10007  }
10008  }
10009  else if(Index == 15)
10010  {
10011  if(TrackElement.SpeedTag == 51)
10012  {
10013  BrNum = 3 + 16;
10014  }
10015  else if(TrackElement.SpeedTag == 53)
10016  {
10017  BrNum = 7 + 16;
10018  }
10019  else if(TrackElement.SpeedTag == 56)
10020  {
10021  BrNum = 5 + 16;
10022  }
10023  }
10024  }
10025  if(!FirstTrack && (TrackElement.TrackType == Bridge))
10026  {
10027  GrNum = BrNum;
10028  }
10029  else
10030  {
10031  GrNum = Index;
10032  }
10033 
10034 //get basic track bitmap
10035  if(GrNum > 15) // underbridge
10036  {
10037  Bitmap = RailGraphics->BridgeGraphicsPtr[GrNum - 16];
10038  }
10039  else
10040  {
10041  Bitmap = RailGraphics->LinkGraphicsPtr[GrNum];
10042  }
10043  if(TrackElement.SpeedTag == 64)
10044  {
10045  Bitmap = RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10046  }
10047  if(TrackElement.SpeedTag == 65)
10048  {
10049  Bitmap = RailGraphics->LinkGraphicsPtr[17];
10050  }
10051  if(TrackElement.SpeedTag == 66)
10052  {
10053  Bitmap = RailGraphics->LinkGraphicsPtr[18];
10054  }
10055  if(TrackElement.SpeedTag == 67)
10056  {
10057  Bitmap = RailGraphics->LinkGraphicsPtr[19];
10058  }
10059  if(TrackElement.SpeedTag == 80)
10060  {
10061  Bitmap = RailGraphics->LinkGraphicsPtr[20]; // intercept continuations to show the dots
10062  }
10063  if(TrackElement.SpeedTag == 81)
10064  {
10065  Bitmap = RailGraphics->LinkGraphicsPtr[21];
10066  }
10067  if(TrackElement.SpeedTag == 82)
10068  {
10069  Bitmap = RailGraphics->LinkGraphicsPtr[22];
10070  }
10071  if(TrackElement.SpeedTag == 83)
10072  {
10073  Bitmap = RailGraphics->LinkGraphicsPtr[23];
10074  }
10075  if(TrackElement.SpeedTag == 84)
10076  {
10077  Bitmap = RailGraphics->LinkGraphicsPtr[24];
10078  }
10079  if(TrackElement.SpeedTag == 85)
10080  {
10081  Bitmap = RailGraphics->LinkGraphicsPtr[25];
10082  }
10083  if(TrackElement.SpeedTag == 86)
10084  {
10085  Bitmap = RailGraphics->LinkGraphicsPtr[26];
10086  }
10087  if(TrackElement.SpeedTag == 87)
10088  {
10089  Bitmap = RailGraphics->LinkGraphicsPtr[27];
10090  }
10091  if(TrackElement.SpeedTag == 129)
10092  {
10093  Bitmap = RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
10094  }
10095  if(TrackElement.SpeedTag == 130)
10096  {
10097  Bitmap = RailGraphics->LinkGraphicsPtr[29];
10098  }
10099 
10100 // RailGraphics->HeatMapGraphic->Assign(Bitmap); //make a copy prior to colouring <- no good, copies bits per pixel too
10101  TRect Rect(0,0,16,16);
10102  RailGraphics->HeatMapGraphic->Canvas->CopyRect(Rect, Bitmap->Canvas, Rect); //this is better, high colour resolution retained
10103  RailGraphics->HeatMapGraphic->TransparentColor = Utilities->clTransparent;
10104  //determine color required
10105  int Red, Green, Blue; //int values will be between 0 & 255
10106  int *R = &Red, *G = &Green, *B = &Blue;
10107  TColor Col;
10108  float Len, Spd;
10109  if(LengthHeatMapFlag)
10110  {
10111  if(Utilities->RedLowFlag)
10112  {
10113  Len = Length/10;
10114  }
10115  else
10116  {
10117  Len = 3000/Length;
10118  }
10119  RailGraphics->GetHeatMapColor(0, (Ln(Len))/5.704, R, G, B); //Len/10 makes range 1 to limit of 300, representing 3000km per element {3000/Len] for reverse spectrum
10120  Col = TColor((65536 * Blue) + (256 * Green) + Red); //5.704 normalises Ln range to between 0 & 1
10122  } //use ChangeForegroundColour2 as faster
10123  else if (SpeedHeatMapFlag)
10124  {
10125  if(Utilities->RedLowFlag)
10126  {
10127  Spd = Speed/10;
10128  }
10129  else
10130  {
10131  Spd = 400/Speed;
10132  }
10133  RailGraphics->GetHeatMapColor(1, (Ln(Spd))/3.691, R, G, B); //Spd/10 makes range 1 to limit of 40, representing 400km/h [400/Spd] for reverse spectrum
10134  Col = TColor((65536 * Blue) + (256 * Green) + Red); //3.691 normalises Ln range to between 0 & 1
10136  } //use ChangeForegroundColour2 as faster
10137  else
10138  {
10139  Utilities->CallLogPop(2721);
10140  return;
10141  }
10142  Disp->PlotOutput(289, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->HeatMapGraphic);
10143  Utilities->CallLogPop(2723);
10144 }
10145 
10146 // ---------------------------------------------------------------------------
10147 
10148 void TTrack::MarkOneLengthandSpeed(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
10149 /*
10150  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
10151  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
10152  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
10153  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
10154  track as indicated by FirstTrack (true for track01 & false for track23).
10155 */
10156 {
10157  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLengthandSpeed," + TrackElement.LogTrack(8) + "," +
10158  AnsiString((short)FirstTrack));
10159  bool LengthDifferent = false, SpeedDifferent = false; //BrNum = bridge number, GrNum = graphic number
10160 
10161  if(IsElementDefaultLengthAndSpeed(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
10162  {
10163  Utilities->CallLogPop(619);
10164  return;
10165  }
10166  int EXArray[16][2] =
10167  {{4, 6}, {2, 8}, // horizontal & vertical
10168  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
10169  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
10170  {1, 9}, {3, 7}}; // forward & reverse diagonals
10171 
10172  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
10173  Graphics::TBitmap *Bitmap;
10174 
10175  if(FirstTrack)
10176  {
10177  InLink = TrackElement.Link[0];
10178  OutLink = TrackElement.Link[1];
10179  }
10180  else
10181  {
10182  InLink = TrackElement.Link[2];
10183  OutLink = TrackElement.Link[3];
10184  }
10185  for(int x = 0; x < 16; x++)
10186  {
10187  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
10188  {
10189  Index = x;
10190  }
10191  }
10192  if(Index == -1)
10193  {
10194  throw Exception("Error, failed to find Index in TTrack::MarkOneLengthandSpeed");
10195  }
10196 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
10197  the graphic for each of which is different because of the shape of the overbridge. The basic
10198  entry/exit value is computed above, and this used to select only from elements with that entry/exit
10199  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
10200  Note that the underbridge track always uses links 2 & 3
10201  int BrEXArray[24][2] = {
10202  {4,6},{2,8},{1,9},{3,7},
10203  {1,9},{3,7},{1,9},{3,7},
10204  {2,8},{4,6},{2,8},{4,6}
10205 */
10206  if(!FirstTrack && (TrackElement.TrackType == Bridge)) //underbridge track always uses links 2 & 3 so never FirstTrack
10207  {
10208  if(Index == 1)
10209  {
10210  if(TrackElement.SpeedTag == 49)
10211  {
10212  BrNum = 1 + 16;
10213  }
10214  else if(TrackElement.SpeedTag == 54)
10215  {
10216  BrNum = 8 + 16;
10217  }
10218  else if(TrackElement.SpeedTag == 55)
10219  {
10220  BrNum = 10 + 16;
10221  }
10222  }
10223  else if(Index == 0)
10224  {
10225  if(TrackElement.SpeedTag == 48)
10226  {
10227  BrNum = 0 + 16;
10228  }
10229  else if(TrackElement.SpeedTag == 58)
10230  {
10231  BrNum = 11 + 16;
10232  }
10233  else if(TrackElement.SpeedTag == 59)
10234  {
10235  BrNum = 9 + 16;
10236  }
10237  }
10238  else if(Index == 14)
10239  {
10240  if(TrackElement.SpeedTag == 50)
10241  {
10242  BrNum = 2 + 16;
10243  }
10244  else if(TrackElement.SpeedTag == 52)
10245  {
10246  BrNum = 4 + 16;
10247  }
10248  else if(TrackElement.SpeedTag == 57)
10249  {
10250  BrNum = 6 + 16;
10251  }
10252  }
10253  else if(Index == 15)
10254  {
10255  if(TrackElement.SpeedTag == 51)
10256  {
10257  BrNum = 3 + 16;
10258  }
10259  else if(TrackElement.SpeedTag == 53)
10260  {
10261  BrNum = 7 + 16;
10262  }
10263  else if(TrackElement.SpeedTag == 56)
10264  {
10265  BrNum = 5 + 16;
10266  }
10267  }
10268  }
10269  if(!FirstTrack && (TrackElement.TrackType == Bridge))
10270  {
10271  GrNum = BrNum;
10272  }
10273  else
10274  {
10275  GrNum = Index;
10276  }
10277  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
10278  {
10279  if(GrNum > 15) // underbridge
10280  {
10281  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
10282  }
10283  else
10284  {
10285  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
10286  }
10287  if(TrackElement.SpeedTag == 64)
10288  {
10289  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10290  }
10291  if(TrackElement.SpeedTag == 65)
10292  {
10294  }
10295  if(TrackElement.SpeedTag == 66)
10296  {
10298  }
10299  if(TrackElement.SpeedTag == 67)
10300  {
10302  }
10303  if(TrackElement.SpeedTag == 80)
10304  {
10305  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
10306  }
10307  if(TrackElement.SpeedTag == 81)
10308  {
10310  }
10311  if(TrackElement.SpeedTag == 82)
10312  {
10314  }
10315  if(TrackElement.SpeedTag == 83)
10316  {
10318  }
10319  if(TrackElement.SpeedTag == 84)
10320  {
10322  }
10323  if(TrackElement.SpeedTag == 85)
10324  {
10326  }
10327  if(TrackElement.SpeedTag == 86)
10328  {
10330  }
10331  if(TrackElement.SpeedTag == 87)
10332  {
10334  }
10335  if(TrackElement.SpeedTag == 129)
10336  {
10337  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
10338  }
10339  if(TrackElement.SpeedTag == 130)
10340  {
10342  }
10343  }
10344 
10345  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
10346  {
10347  if(GrNum > 15) // underbridge
10348  {
10349  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
10350  }
10351  else
10352  {
10353  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
10354  }
10355  if(TrackElement.SpeedTag == 64)
10356  {
10357  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10358  }
10359  if(TrackElement.SpeedTag == 65)
10360  {
10361  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
10362  }
10363  if(TrackElement.SpeedTag == 66)
10364  {
10365  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
10366  }
10367  if(TrackElement.SpeedTag == 67)
10368  {
10369  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
10370  }
10371  if(TrackElement.SpeedTag == 80)
10372  {
10373  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10374  }
10375  if(TrackElement.SpeedTag == 81)
10376  {
10377  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
10378  }
10379  if(TrackElement.SpeedTag == 82)
10380  {
10381  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
10382  }
10383  if(TrackElement.SpeedTag == 83)
10384  {
10385  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
10386  }
10387  if(TrackElement.SpeedTag == 84)
10388  {
10389  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
10390  }
10391  if(TrackElement.SpeedTag == 85)
10392  {
10393  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
10394  }
10395  if(TrackElement.SpeedTag == 86)
10396  {
10397  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
10398  }
10399  if(TrackElement.SpeedTag == 87)
10400  {
10401  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
10402  }
10403  if(TrackElement.SpeedTag == 129)
10404  {
10405  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
10406  }
10407  if(TrackElement.SpeedTag == 130)
10408  {
10409  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
10410  }
10411  }
10412 
10413  else // SpeedDifferent only: red - use non sig graphics
10414  {
10415  if(GrNum > 15) // underbridge
10416  {
10417  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
10418  }
10419  else
10420  {
10421  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
10422  }
10423  if(TrackElement.SpeedTag == 64)
10424  {
10425  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10426  }
10427  if(TrackElement.SpeedTag == 65)
10428  {
10430  }
10431  if(TrackElement.SpeedTag == 66)
10432  {
10434  }
10435  if(TrackElement.SpeedTag == 67)
10436  {
10438  }
10439  if(TrackElement.SpeedTag == 80)
10440  {
10441  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10442  }
10443  if(TrackElement.SpeedTag == 81)
10444  {
10446  }
10447  if(TrackElement.SpeedTag == 82)
10448  {
10450  }
10451  if(TrackElement.SpeedTag == 83)
10452  {
10454  }
10455  if(TrackElement.SpeedTag == 84)
10456  {
10458  }
10459  if(TrackElement.SpeedTag == 85)
10460  {
10462  }
10463  if(TrackElement.SpeedTag == 86)
10464  {
10466  }
10467  if(TrackElement.SpeedTag == 87)
10468  {
10470  }
10471  if(TrackElement.SpeedTag == 129)
10472  {
10473  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10474  }
10475  if(TrackElement.SpeedTag == 130)
10476  {
10478  }
10479  }
10480  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10481  Utilities->CallLogPop(620);
10482 }
10483 
10484 // ---------------------------------------------------------------------------
10485 
10486 bool TTrack::IsElementDefaultLengthAndSpeed(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10487 /* FirstTrack = LinkPos's 0 & 1
10488  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10489 */
10490 {
10491  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementDefaultLengthAndSpeed," + TrackElement.LogTrack(10) + "," +
10492  AnsiString((short)FirstTrack));
10493  LengthDifferent = false;
10494  SpeedDifferent = false;
10495  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10496  {
10497  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10498  {
10499  LengthDifferent = true;
10500  }
10501  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10502  {
10503  SpeedDifferent = true;
10504  }
10505  if(LengthDifferent || SpeedDifferent)
10506  {
10507  Utilities->CallLogPop(625);
10508  return(false);
10509  }
10510  Utilities->CallLogPop(626);
10511  return(true);
10512  }
10513 
10514  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10515  {
10516  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10517  {
10518  LengthDifferent = true;
10519  }
10520  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10521  {
10522  SpeedDifferent = true;
10523  }
10524  if(LengthDifferent || SpeedDifferent)
10525  {
10526  Utilities->CallLogPop(627);
10527  return(false);
10528  }
10529  Utilities->CallLogPop(628);
10530  return(true);
10531  }
10532 
10533  else // any other 1 track element, including platforms being present
10534  {
10535  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10536  {
10537  LengthDifferent = true;
10538  }
10539  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10540  {
10541  SpeedDifferent = true;
10542  }
10543  if(LengthDifferent || SpeedDifferent)
10544  {
10545  Utilities->CallLogPop(629);
10546  return(false);
10547  }
10548  Utilities->CallLogPop(630);
10549  return(true);
10550  }
10551 }
10552 
10553 // ---------------------------------------------------------------------------
10554 
10555 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10556 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10557 {
10558  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10559  AnsiString(VLoc));
10560  bool FoundFlag;
10561  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10562 
10563  if(!FoundFlag)
10564  {
10565  Utilities->CallLogPop(633);
10566  return(false);
10567  }
10568  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10569  {
10570  Utilities->CallLogPop(634);
10571  return(true); // only need to check first since if second is a platform the the first must be too
10572  }
10573  else
10574  {
10575  Utilities->CallLogPop(635);
10576  return(false);
10577  }
10578 }
10579 
10580 // ---------------------------------------------------------------------------
10581 
10582 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10583 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10584 {
10585  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10586  AnsiString(VLoc));
10587  bool FoundFlag;
10588  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10589 
10590  if(!FoundFlag)
10591  {
10592  Utilities->CallLogPop(636);
10593  return(false);
10594  }
10596  {
10597  Utilities->CallLogPop(637);
10598  return(true); // only need to check first since only one used for NamedNonStationLocations
10599  }
10600  else
10601  {
10602  Utilities->CallLogPop(638);
10603  return(false);
10604  }
10605 }
10606 
10607 // ---------------------------------------------------------------------------
10608 
10609 void TTrack::SetStationEntryStopLinkPosses(int Caller) //only for platforms
10610 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10611  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10612  the front of train stop points for each direction.
10613  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10614  end (unless buffers at one or both ends in which case stop points are the end elements).
10615  Note that for a single element the stop point is the element itself (formula doesn't apply).
10616  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10617  repeating the procedure for every element. At the end all unused values are returned to -1.
10618  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10619 */
10620 {
10621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10622  TTrackElement TempElement, StartElement;
10623  AnsiString TempName;
10624  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10625  bool ForwardSet, ReverseSet;
10626 
10627  for(unsigned int x = 0; x < TrackVector.size(); x++)
10628  {
10629  TrackElementAt(1378, x).StationEntryStopLinkPos1 = -1; //this only sets 0 & 1 as all single track elements for platforms
10631  }
10632  for(unsigned int x = 0; x < TrackVector.size(); x++)
10633  {
10634  TempElement = TrackElementAt(1380, x);
10635  if(!IsNamedNonStationLocationPresent(2, TempElement.HLoc, TempElement.VLoc)) //deal with non-station names later
10636  {
10637  ForwardSet = false;
10638  ReverseSet = false;
10639  VecPos = x;
10640  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1) && (TempElement.StationEntryStopLinkPos2 == -1))
10641  // 2nd condition incl so don't re-examine elements with stop links set to 5
10642  {
10643  TempName = TempElement.ActiveTrackElementName;
10644  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10645  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10646  // an element linked at both ends where both links are also named elements
10647  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10648  {
10649  continue; // looking for an end element so skip this one
10650  }
10651  else // reached one end
10652  {
10653  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10654  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10655  // single named element linked at both ends, can't be continuation as platforms not allowed there
10656  {
10657  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10658  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10659  continue;
10660  }
10661  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10662  // single named buffer element (LinkPos 1 is the non-buffer end)
10663  {
10664  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10665  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10666  continue;
10667  }
10668  else
10669  // Note: only interested in connection positions 0 & 1 since all platform elements are single track except points,
10670  // and platforms always on straight (conns 0 & 1) section of points
10671  {
10672  for(int y = 0; y < 2; y++)
10673  {
10674  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10675  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10676  /* TTrackElement Temp1 = TempElement;
10677  ***********New section, compiles but not checked - does bit below need to be else if?
10678  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10679  {
10680  //search along Dir direction until find other end, skip if Dir facing buffer end
10681  int NewDir = Dir;
10682  int NewVecPos;
10683  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10684  {
10685  NewVecPos = Temp1.Conn[NewDir];
10686  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10687  Temp1 = TrackElementAt(601, NewVecPos);
10688  }
10689  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10690  {
10691  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10692  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10693  }
10694  }
10695  ***************
10696  */
10697  // end may be linked at both ends but only one link named, or buffer with linked element named
10698  // if a buffer then the named linkpos has to be 1
10699  // already dealt with all types of single element so at least 2 linked named elements
10700  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10701  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10702  { //element linked at both ends with entry end not same name, or buffers with exit link == 1 (exit link always 1 but need to ensure Dir set correctly)
10703  StartElement = TempElement;
10704  StartVecPos = VecPos; //this stays fixed at start of platform group
10705  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10706  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10707  EntryPos = 1 - Dir;
10708  StartEntryPos = 1 - Dir;
10709  Count = 1;
10710  // work along named elements until find the other end
10711  while((TempElement.Conn[1 - EntryPos] > -1) && (TempElement.Conn[1 - EntryPos] < (int)TrackVector.size()) && (TrackElementAt(53, TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10712  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10713  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10714  // all stop link pos's are set to 5
10715  {
10716  VecPos = TempElement.Conn[1 - EntryPos];
10717  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10718  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10719  EntryPos = TempEntryPos;
10720  Count++;
10721  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10722  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10723  }
10724  // here when reached other end, maybe buffers, or last named linked element
10725  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10726  // terminal station, set end elements as stop elements
10727  {
10728  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10729  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10730  continue;
10731  }
10732  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10733  // terminal station, set end elements as stop elements
10734  {
10735  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10736  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10737  continue;
10738  }
10739  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10740  ForwardNumber = ((Count + 1) / 2) + 1;
10741  ReverseNumber = (Count - ForwardNumber) + 1;
10742  Count = 1; // starting value
10743  EntryPos = 1 - Dir;
10744  TempElement = StartElement;
10745  VecPos = StartVecPos;
10746  if(Count == ForwardNumber)
10747  {
10748  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10749  ForwardSet = true;
10750  }
10751  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10752  {
10753  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10754  ReverseSet = true;
10755  }
10756  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10757  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10758  {
10759  VecPos = TempElement.Conn[1 - EntryPos];
10760  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10761  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10762  EntryPos = TempEntryPos;
10763  Count++;
10764  if(Count == ForwardNumber)
10765  {
10766  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10767  ForwardSet = true;
10768  }
10769  if(Count == ReverseNumber)
10770  {
10771  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10772  ReverseSet = true;
10773  }
10774  }
10775  }
10776  }
10777  }
10778  }
10779  }
10780  }
10781  }
10782  for(unsigned int x = 0; x < TrackVector.size(); x++)
10783  {
10784  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10785  {
10787  }
10788  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10789  {
10791  }
10792  }
10793  Utilities->CallLogPop(639);
10794 }
10795 
10796 // ---------------------------------------------------------------------------
10797 
10798 void TTrack::SetNonStationStopLinkEntryPosses(int Caller) //added at v2.18.0
10799 
10800 {
10801 /*at v2.18.0 allow for 2 tracks on a non-station element. Have StationEntryStopLinkPos1 & 2 contain both track entry positions, 0 & 1 in
10802 least sig 2 bits and 2 & 3 in next least sig bits. In use have SESLPos1a == 0 or 1 and SESLPos1b == 2 or 3, and same for Pos2. 'b' values all
10803 set to 0 for platforms, and set appropriately for 2-track non-station locs. SESLPos values are TTrackElement variables only used in program, not
10804 saved in sessions or railways (same as StationEntryStopLinkPos1 & 2).
10805 
10806 Examine each non-station area with same name and, similar to above, look for cases where a track doesn't link to an element with the same name, or
10807 doesn't link at all, this is an end element, check both tracks separately for 4-track elements.
10808 */
10809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetNonStationStopLinkEntryPosses");
10810  TTrackElement TempElement;
10811  AnsiString TempName;
10812  std::list<unsigned int> NameList; //end elements
10813  std::list<AnsiString> ContinuationNameList; // list of continuation names so can exclude them
10814  for(unsigned int x = 0; x < TrackVector.size(); x++)
10815  {
10816  TrackElementAt(1594, x).StationEntryStopLinkPos3 = -1; // don't clear stopping points 0 & 1 as already set for platforms
10818  if((TrackElementAt(1596, x).TrackType == Continuation) && (TrackElementAt(1641, x).ActiveTrackElementName != ""))
10819  {
10820  ContinuationNameList.push_back(TrackElementAt(1597, x).ActiveTrackElementName);
10821  }
10822  }
10823  ContinuationNameList.sort();
10824  ContinuationNameList.unique();
10825 
10826  for(unsigned int x = 0; x < TrackVector.size(); x++)
10827  {
10828  TempElement = TrackElementAt(1598, x);
10829  if(IsNamedNonStationLocationPresent(3, TempElement.HLoc, TempElement.VLoc))
10830  {
10831  bool NameIsAContinuation = false;
10832  if(std::find(ContinuationNameList.begin(), ContinuationNameList.end(), TempElement.ActiveTrackElementName) != ContinuationNameList.end())
10833  {
10834  NameIsAContinuation = true;
10835  }
10836  if((TempElement.ActiveTrackElementName != "") && !NameIsAContinuation && (TempElement.StationEntryStopLinkPos1 == -1) &&
10837  (TempElement.StationEntryStopLinkPos2 == -1) && (TempElement.StationEntryStopLinkPos3 == -1) && (TempElement.StationEntryStopLinkPos4 == -1))
10838  // Non-station named elements can't be placed on platforms so no conflict with existing stop positions
10839  {
10840  TempName = TempElement.ActiveTrackElementName;
10841  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(1599, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10842  (TrackElementAt(1600, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10843  // an element linked at both ends of single or main track where both links are also named elements with same name
10844  {
10845  if(TempElement.TrackType == Points) //for points links 0 and 2 are the same
10846  {
10847  if(((TempElement.Conn[2] > -1)) && (TempElement.Conn[3] > -1) &&
10848  ((TrackElementAt(1601, TempElement.Conn[2]).ActiveTrackElementName == TempName)) &&
10849  (TrackElementAt(1602, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10850  {
10851  continue; //not an end element so skip it
10852  }
10853  else //reached an end on the diverging leg
10854  {
10855  NameList.push_back(x);
10856  }
10857  }
10858  else if(TempElement.TrackType == Crossover)
10859  {
10860  if((TempElement.Conn[2] > -1) && (TempElement.Conn[3] > -1) &&
10861  (TrackElementAt(1603, TempElement.Conn[2]).ActiveTrackElementName == TempName) &&
10862  (TrackElementAt(1604, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10863  {
10864  continue; //not an end element so skip it
10865  }
10866  else
10867  {
10868  NameList.push_back(x);
10869  }
10870  }
10871  else
10872  {
10873  continue; //not points ot crossover & not an end element so skip
10874  }
10875  }
10876  else // reached one end of single or main track
10877  {
10878  NameList.push_back(x);
10879  }
10880 //NameList now contains all non-station end elements
10881  while(!NameList.empty())
10882  {
10883  unsigned int a = NameList.front();
10884  NameList.pop_front();
10885  TTrackElement &TempElement = TrackElementAt(1605, a);
10886  AnsiString TempName = TempElement.ActiveTrackElementName;
10887  if(TempElement.TrackType == Buffers) //buffer end is 0 so entry must be 1, gaps covered below as any other element
10888  {
10889  TempElement.StationEntryStopLinkPos1 = 1;
10890  }
10891  else
10892  {
10893  if((TempElement.Conn[0] == -1) || (TrackElementAt(1606, TempElement.Conn[0]).ActiveTrackElementName != TempName))
10894  {
10895  TempElement.StationEntryStopLinkPos1 = 1;
10896  }
10897  if((TempElement.Conn[1] == -1) || (TrackElementAt(1607, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10898  {
10899  TempElement.StationEntryStopLinkPos2 = 0;
10900  }
10901  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover))
10902  {
10903  if((TempElement.Conn[2] == -1) || (TrackElementAt(1608, TempElement.Conn[2]).ActiveTrackElementName != TempName))
10904  {
10905  TempElement.StationEntryStopLinkPos3 = 3;
10906  }
10907  if((TempElement.Conn[3] == -1) || (TrackElementAt(1609, TempElement.Conn[3]).ActiveTrackElementName != TempName))
10908  {
10909  TempElement.StationEntryStopLinkPos4 = 2;
10910  }
10911  }
10912  }
10913  }
10914  }
10915  }
10916  }
10917  Utilities->CallLogPop(2640);
10918 }
10919 
10920 // ---------------------------------------------------------------------------
10921 
10922 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10923 {
10924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10925  TTrackElement Next;
10926 
10928  while(ReturnNextInactiveTrackElement(1, Next))
10929  {
10930  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10931  {
10932  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10933  // need striped graphics
10934  {
10935  if(Next.SpeedTag == 76)
10936  {
10937  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10938  }
10939  else if(Next.SpeedTag == 77)
10940  {
10941  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10942  }
10943  else if(Next.SpeedTag == 78)
10944  {
10945  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10946  }
10947  else if(Next.SpeedTag == 79)
10948  {
10949  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10950  }
10951  else if(Next.SpeedTag == 96)
10952  {
10953  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10954  }
10955  else if(Next.SpeedTag == 131)
10956  {
10957  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10958  }
10959  }
10960  else
10961  {
10962  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10963  }
10964  }
10965  }
10966 
10967  NextTrackElementPtr = TrackVector.begin();
10968  while(ReturnNextTrackElement(1, Next))
10969  {
10970  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10971  {
10972  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10973  {
10974  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10975  {
10976  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10977  }
10978  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10979  {
10980  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10981  }
10982  }
10983  else
10984  {
10985  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10986  }
10987  }
10988  }
10989  Disp->Update();
10990  Utilities->CallLogPop(640);
10991 }
10992 
10993 // ---------------------------------------------------------------------------
10994 
10995 void TTrack::PlotSmallRedGap(int Caller)
10996 {
10997  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10999  Utilities->CallLogPop(1346);
11000 }
11001 
11002 // ---------------------------------------------------------------------------
11003 
11004 void TTrack::TrackClear(int Caller)
11005 {
11006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
11007  TrackVector.clear();
11008  InactiveTrackVector.clear();
11009  TrackMap.clear();
11011  if(TextHandler->TextVector.size() == 0)
11012  {
11013  Display->DisplayOffsetH = 0;
11014  Display->DisplayOffsetV = 0;
11021  HLocMin = 2000000000;
11022  HLocMax = -2000000000;
11023  VLocMin = 2000000000;
11024  VLocMax = -2000000000;
11025  }
11026  else
11027  {
11028  CalcHLocMinEtc(4);
11029  }
11030  Utilities->CallLogPop(1347);
11031 }
11032 
11033 // ---------------------------------------------------------------------------
11034 
11035 void TTrack::CalcHLocMinEtc(int Caller)
11036 {
11037  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
11038  HLocMin = 2000000000;
11039  VLocMin = 2000000000;
11040  HLocMax = -2000000000;
11041  VLocMax = -2000000000;
11042  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
11043  {
11044  if(TrackElementAt(1385, x).SpeedTag == 0)
11045  {
11046  continue; // skip erase elements or would interfere with Min & Max values
11047  }
11048  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
11049  {
11050  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
11051  }
11052  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
11053  {
11054  HLocMax = TrackElementAt(1389, x).HLoc + 1;
11055  }
11056  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
11057  {
11058  VLocMin = TrackElementAt(1391, x).VLoc - 1;
11059  }
11060  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
11061  {
11062  VLocMax = TrackElementAt(1393, x).VLoc + 1;
11063  }
11064  }
11065  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
11066  {
11067  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
11068  {
11069  continue; // shouldn't be any inactive erase elements but include anyway
11070  }
11071  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
11072  {
11073  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
11074  }
11075  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
11076  {
11077  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
11078  }
11079  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
11080  {
11081  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
11082  }
11083  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
11084  {
11085  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
11086  }
11087  }
11088  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
11089  {
11090 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
11091  will fail as x will exceed the maximum value
11092  if(TextHandler->TextPtrAt(, x)->TextString == "")
11093  {
11094  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
11095  }
11096 */
11097  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
11098  if((TextH / 16) - 1 < HLocMin)
11099  {
11100  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
11101  }
11102  if((TextH / 16) + 1 > HLocMax)
11103  {
11104  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
11105  }
11106  if((TextV / 16) - 1 < VLocMin)
11107  {
11108  VLocMin = (TextV / 16) - 1;
11109  }
11110  if((TextV / 16) + 1 > VLocMax)
11111  {
11112  VLocMax = (TextV / 16) + 1;
11113  }
11114  }
11115  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
11116  {
11117  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
11118  {
11119  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
11120  }
11121  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
11122  {
11123  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
11124  }
11125  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
11126  {
11127  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
11128  }
11129  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
11130  {
11131  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
11132  }
11133  }
11134 
11135  Utilities->CallLogPop(641);
11136 }
11137 
11138 // ---------------------------------------------------------------------------
11139 
11140 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
11141  bool &UserGraphicFoundFlag)
11142 {
11143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
11144  TUserGraphicVector::iterator UserGraphicPtr;
11145 
11146  UserGraphicFoundFlag = false;
11147  if(!UserGraphicVector.empty())
11148  {
11149  int x = UserGraphicVector.size();
11150  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
11151  {
11152  x--;
11153  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
11154  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
11155  {
11156  UserGraphicItem = x;
11157  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
11158  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
11159  UserGraphicFoundFlag = true;
11160  Utilities->CallLogPop(2177);
11161  return;
11162  } // if ....
11163 
11164  } // for UserGraphicPtr...
11165  } // if !UserGraphicVector...
11166 
11167  Utilities->CallLogPop(2197);
11168 }
11169 
11170 // ---------------------------------------------------------------------------
11171 
11173 {
11174  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
11175  TrackElement.LogTrack(11));
11176  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
11177  int SpeedTag = TrackElement.SpeedTag;
11178 
11179  if(SpeedTag < 1)
11180  {
11181  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
11182  }
11183  switch(SpeedTag)
11184  {
11185  case 76: // t platform
11186  GraphicOutput = RailGraphics->gl76Striped;
11187  break;
11188 
11189  case 77: // h platform
11190  GraphicOutput = RailGraphics->bm77Striped;
11191  break;
11192 
11193  case 78: // v platform
11194  GraphicOutput = RailGraphics->bm78Striped;
11195  break;
11196 
11197  case 79: // r platform
11198  GraphicOutput = RailGraphics->gl79Striped;
11199  break;
11200 
11201  case 96: // concourse
11202  GraphicOutput = RailGraphics->ConcourseStriped;
11203  break;
11204 
11205  case 129: // v footbridge
11206  GraphicOutput = RailGraphics->gl129Striped;
11207  break;
11208 
11209  case 130: // h footbridge
11210  GraphicOutput = RailGraphics->gl130Striped;
11211  break;
11212 
11213  case 131: // non-station named loc
11214  GraphicOutput = RailGraphics->bmNameStriped;
11215  break;
11216 
11217  case 145: // v u'pass
11218  GraphicOutput = RailGraphics->gl145Striped;
11219  break;
11220 
11221  case 146: // h u'pass
11222  GraphicOutput = RailGraphics->gl146Striped;
11223  break;
11224 
11225  default:
11226  GraphicOutput = TrackElement.GraphicPtr;
11227  break;
11228  }
11229  Utilities->CallLogPop(642);
11230  return(GraphicOutput);
11231 }
11232 
11233 // ---------------------------------------------------------------------------
11234 
11236 {
11237  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
11238  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
11239  {
11240 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
11241  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
11242  }
11243  Utilities->CallLogPop(643);
11244  return(TrackVector.at(At));
11245 }
11246 
11247 // ---------------------------------------------------------------------------
11248 
11250 {
11251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
11252  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
11253  {
11254  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
11255  " in InactiveTrackElementAt");
11256  }
11257  Utilities->CallLogPop(644);
11258  return(InactiveTrackVector.at(At));
11259 }
11260 
11261 // ---------------------------------------------------------------------------
11262 
11263 bool TTrack::BlankElementAt(int Caller, int At) const
11264 {
11265  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
11266  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
11267  {
11268  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
11269  }
11270  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
11271  {
11272  Utilities->CallLogPop(645);
11273  return(true);
11274  }
11275  else
11276  {
11277  Utilities->CallLogPop(646);
11278  return(false);
11279  }
11280 }
11281 
11282 // ---------------------------------------------------------------------------
11283 
11284 bool TTrack::OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
11285 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
11286  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
11287  split is required a specific check is made using ThisStationLongEnoughForSplit.
11288  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
11289  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
11290 */
11291 {
11292  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneStationLongEnoughForSplit," + LocationName);
11293  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11294  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
11295  TLocationNameMultiMapIterator SNIterator;
11296  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11297 
11298  if(SNRange.first == SNRange.second)
11299  {
11300  Utilities->CallLogPop(972);
11301  return(false); // should have been caught earlier but include for completeness
11302  }
11303  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11304  {
11305  if(SNIterator->second < 0)
11306  {
11307  continue; // exclude footcrossings
11308  }
11309  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
11310  if(InactiveElement.TrackType == Concourse)
11311  {
11312  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11313  }
11314  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11315  {
11316  continue; // only interested in locations where ActiveTrackElementName may be set
11317  }
11318  THVPair HVPair;
11319  HVPair.first = InactiveElement.HLoc;
11320  HVPair.second = InactiveElement.VLoc;
11321  if(TrackMap.find(HVPair) == TrackMap.end())
11322  {
11323  throw Exception
11324  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneStationLongEnoughForSplit (1)");
11325  }
11326  int TVPos = TrackMap.find(HVPair)->second;
11327  FirstNamedElement = TrackElementAt(560, TVPos);
11328  // first check linked on both sides, skip the check if not
11329  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
11330  {
11331  continue;
11332  }
11333  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
11334  // ActiveTrackElementNames are points and excluding trailing connections for points
11335  FirstNamedExitPos = 0;
11336  {
11337  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
11338  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11339  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11340  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11341  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11342  {
11343  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11344  {
11345  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
11346  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11347  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11348  // success, now check FirstNamedElement link not trailing points & if so all OK
11349  {
11350  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11351  {
11352  Utilities->CallLogPop(1002);
11353  return(true);
11354  }
11355  }
11356  }
11357  }
11358  }
11359  // failed, try link 1
11360  FirstNamedExitPos = 1;
11361  {
11362  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
11363  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11364  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11365  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11366  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11367  {
11368  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11369  {
11370  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
11371  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11372  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11373  // success, now check FirstNamedElement link not trailing points & if so all OK
11374  {
11375  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11376  {
11377  Utilities->CallLogPop(1003);
11378  return(true);
11379  }
11380  }
11381  }
11382  }
11383  }
11384  }
11385  Utilities->CallLogPop(1004);
11386  return(false);
11387 }
11388 
11389 // ---------------------------------------------------------------------------
11390 
11391 bool TTrack::OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName) //changed at v2.18.0
11392 /* Check sufficient active elements at same H & V as the non-station element with same ActiveTrackElementName linked together to allow a train split.
11393  Only one train length is needed to return true, but this doesn't mean that all tracks at the location are long enough. When a
11394  split is required a specific check is made using ThisLocationLongEnoughForSplit.
11395  Need at least two linked ActiveTrackElementNames, with connected elements at each end, or three if one end is a buffer, but no need to check
11396  buffers explicitly as it will come out automatically with the logic applied.
11397  Note that these conditions exclude opposed buffers since these not linked.
11398 */
11399 {
11400  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNonStationLongEnoughForSplit," + LocationName);
11401  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11402  int FirstNamedExitPos, SecondNamedEntryPos, SecondNamedExitPos;
11403  TLocationNameMultiMapIterator SNIterator;
11404  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11405 
11406  if(SNRange.first == SNRange.second)
11407  {
11408  Utilities->CallLogPop(2641);
11409  return(false); // should have been caught earlier but include for completeness
11410  }
11411  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11412  {
11413  if(SNIterator->second < 0) //negative numbers represent active track elements
11414  {
11415  continue; // exclude footcrossings - only these have active track element names
11416  }
11417  InactiveElement = InactiveTrackElementAt(1412, SNIterator->second);
11418  if(InactiveElement.TrackType == Concourse)
11419  {
11420  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11421  }
11422  if(!TrackElementPresentAtHV(2, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11423  {
11424  continue; // only interested in locations where ActiveTrackElementName may be set
11425  }
11426  THVPair HVPair;
11427  HVPair.first = InactiveElement.HLoc;
11428  HVPair.second = InactiveElement.VLoc;
11429  if(TrackMap.find(HVPair) == TrackMap.end())
11430  {
11431  throw Exception ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNonStationLongEnoughForSplit(1)");
11432  }
11433  int TVPos = TrackMap.find(HVPair)->second;
11434  FirstNamedElement = TrackElementAt(1610, TVPos);
11435  // first check linked on both sides, skip the check if not
11436  if(((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) && ((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)))
11437  {
11438  continue;
11439  }
11440  // check if another ActiveTrackElementName connected via a link
11441  if((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)) //examine connections at links 0 & 1
11442  {
11443  FirstNamedExitPos = 0; //this is the end linked to the second named element
11444  {
11445  SecondNamedElement = TrackElementAt(1611, FirstNamedElement.Conn[FirstNamedExitPos]);
11446  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11447  {
11448  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11449  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11450  {
11451  SecondNamedExitPos = 1 - SecondNamedEntryPos; //SecondNamedExitPos is the end not linked to FirstNamedElement
11452  }
11453  else if(SecondNamedEntryPos == 2)
11454  {
11455  SecondNamedExitPos = 3;
11456  }
11457  else if(SecondNamedEntryPos == 3)
11458  {
11459  SecondNamedExitPos = 2;
11460  }
11461  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11462  {
11463  Utilities->CallLogPop(2642);
11464  return(true);
11465  } //if not try other exitpos
11466  }
11467  }
11468  FirstNamedExitPos = 1;
11469  {
11470  SecondNamedElement = TrackElementAt(1612, FirstNamedElement.Conn[FirstNamedExitPos]);
11471  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11472  {
11473  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11474  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11475  {
11476  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11477  }
11478  else if(SecondNamedEntryPos == 2)
11479  {
11480  SecondNamedExitPos = 3;
11481  }
11482  else if(SecondNamedEntryPos == 3)
11483  {
11484  SecondNamedExitPos = 2;
11485  }
11486  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11487  {
11488  Utilities->CallLogPop(2643);
11489  return(true);
11490  } //failed so far, try links 2 & 3, one or other must be linked on both side or would have continued
11491  }
11492  }
11493  }
11494  else if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) //examine connections at links 2 & 3
11495  {
11496  FirstNamedExitPos = 2;
11497  {
11498  SecondNamedElement = TrackElementAt(1613, FirstNamedElement.Conn[FirstNamedExitPos]);
11499  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11500  {
11501  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11502  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11503  {
11504  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11505  }
11506  else if(SecondNamedEntryPos == 2)
11507  {
11508  SecondNamedExitPos = 3;
11509  }
11510  else if(SecondNamedEntryPos == 3)
11511  {
11512  SecondNamedExitPos = 2;
11513  }
11514  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11515  {
11516  Utilities->CallLogPop(2644);
11517  return(true);
11518  } //if not try other exitpos
11519  }
11520  }
11521  FirstNamedExitPos = 3;
11522  {
11523  SecondNamedElement = TrackElementAt(1614, FirstNamedElement.Conn[FirstNamedExitPos]);
11524  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11525  {
11526  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11527  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11528  {
11529  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11530  }
11531  else if(SecondNamedEntryPos == 2)
11532  {
11533  SecondNamedExitPos = 3;
11534  }
11535  else if(SecondNamedEntryPos == 3)
11536  {
11537  SecondNamedExitPos = 2;
11538  }
11539  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11540  {
11541  Utilities->CallLogPop(2645);
11542  return(true);
11543  } //failed so continue to next element or return false
11544  }
11545  }
11546  }
11547  }
11548  Utilities->CallLogPop(2646);
11549  return(false);
11550 }
11551 
11552 // ---------------------------------------------------------------------------
11553 
11554 //new version at v2.18.0
11555 bool TTrack::ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement,
11556  int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
11557 /* Return false if the track that the train is on isn't long enough for a split - only 1 named element or 2 with only one external link.
11558 Otherwise find the best 4 final element positions, preferably with FrontTrainFrontPos on a named element. Conditions are that the original train
11559 will lie within the 4 elements of the two split trains, and at least 1 element of each split train will be at the location. Within those conditions
11560 the lead element of the front train will be at the location if it is possible.
11561 */
11562 {
11563  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisLocationLongEnoughForSplit," + AnsiString(TrainID) + "," +
11564  LocationName + AnsiString(LeadElement) + "," + AnsiString(LeadExitPos) + "," + AnsiString(MidElement) + "," + AnsiString(MidEntryPos));
11565 
11566  TemporaryDelay = false; //used in calling function to set LastActionTime to TTClockTime so failure messages only given every 30 secs
11567  //count forwards from LeadElement - only need to count forwards 2 elements to ptovide for room for new front train
11568  int FwdPos[3] = {LeadElement, -1, -1}; //0 starts at LeadElement and increases as go forwards
11569  int RwdPos[3] = {MidElement, -1, -1}; //0 starts at MidElement and increases as go backwards
11570  TTrackElement FwdPos0Element = TrackElementAt(1666, LeadElement);
11571  TTrackElement RwdPos0Element = TrackElementAt(1667, MidElement);
11572  int FwdPos1EntryPos, FwdPos1ExitPos, FwdPos2EntryPos, FwdPos2ExitPos, RwdPos1EntryPos, RwdPos1ExitPos, RwdPos2EntryPos, RwdPos2ExitPos; //these needed to test for other train on element
11573 
11574  bool FwdDerail1 = false, FwdDerail2 = false, RwdDerail1 = false, RwdDerail2 = false;
11575  int NumFwdNamedElements = 0, NumFwdElements = 0, NumRwdNamedElements = 0, NumRwdElements = 1; //Fwd = ahead of LeadElement, Rwd includes MidElement
11576  if(RwdPos0Element.ActiveTrackElementName == LocationName) //MidElement
11577  {
11578  NumRwdNamedElements = 1;
11579  }
11580 
11581  FwdPos[1] = FwdPos0Element.Conn[LeadExitPos];
11582  if(FwdPos[1] > -1)
11583  {
11584  NumFwdElements = 1;
11585  TTrackElement FwdPos1Element = TrackElementAt(1668, FwdPos[1]);
11586  if(FwdPos1Element.ActiveTrackElementName == LocationName)
11587  {
11588  NumFwdNamedElements = 1;
11589  }
11590  FwdPos1EntryPos = FwdPos0Element.ConnLinkPos[LeadExitPos];
11591  FwdPos1ExitPos = GetAnyElementOppositeLinkPos(4, FwdPos[1], FwdPos1EntryPos, FwdDerail1);
11592  FwdPos[2] = FwdPos1Element.Conn[FwdPos1ExitPos];
11593  if(FwdPos[2] > -1)
11594  {
11595  NumFwdElements = 2;
11596  FwdPos2EntryPos = FwdPos1Element.ConnLinkPos[FwdPos1ExitPos];
11597  FwdPos2ExitPos = GetAnyElementOppositeLinkPos(5, FwdPos[2], FwdPos2EntryPos, FwdDerail2); //this is purely to obtain Derail
11598  TTrackElement FwdPos2Element = TrackElementAt(1669, FwdPos[2]);
11599  if(FwdPos2Element.ActiveTrackElementName == LocationName)
11600  {
11601  NumFwdNamedElements = 2;
11602  }
11603  }
11604  }
11605 //this is as far as need to go forwards
11606 
11607  RwdPos[1] = RwdPos0Element.Conn[MidEntryPos];
11608  if(RwdPos[1] > -1)
11609  {
11610  NumRwdElements = 2; //includes MidElement
11611  TTrackElement RwdPos1Element = TrackElementAt(1670, RwdPos[1]);
11612  if(RwdPos1Element.ActiveTrackElementName == LocationName)
11613  {
11614  NumRwdNamedElements = 2; //includes MidElement (treats MidElement as named even if not, as eventual positions will be same either way)
11615  }
11616  RwdPos1ExitPos = RwdPos0Element.ConnLinkPos[MidEntryPos];
11617  RwdPos1EntryPos = GetAnyElementOppositeLinkPos(6, RwdPos[1], RwdPos1ExitPos, RwdDerail1);
11618  RwdPos[2] = RwdPos1Element.Conn[RwdPos1EntryPos];
11619  if(RwdPos[2] > -1)
11620  {
11621  NumRwdElements = 3; //includes MidElement
11622  RwdPos2ExitPos = RwdPos1Element.ConnLinkPos[RwdPos1EntryPos];
11623  RwdPos2EntryPos = GetAnyElementOppositeLinkPos(7, RwdPos[2], RwdPos2ExitPos, RwdDerail2); //this is purely to obtain Derail
11624  TTrackElement RwdPos2Element = TrackElementAt(1671, RwdPos[2]);
11625  if(RwdPos2Element.ActiveTrackElementName == LocationName)
11626  {
11627  NumRwdNamedElements = 3; //includes MidElement (treats MidElement & next position to rear as both named even if not, as eventual positions will be same either way)
11628  }
11629  }
11630  }
11631 //this is as far as need to go backwards
11632 
11633 //now try to accommodate front train on named elements if possible
11634  if(NumFwdNamedElements == 2)//Front train moves onto the 2 forward named elements & rear train is on original train elements X N N N (N = named, X = named or not)
11635  { // M L - - >> RM RL FM FL
11636  FrontTrainFrontPos = FwdPos[2];
11637  FrontTrainRearPos = FwdPos[1];
11638  RearTrainFrontPos = LeadElement;
11639  RearTrainRearPos = MidElement;
11640  if(FwdDerail1 || FwdDerail2)
11641  {
11642  TrainController->StopTTClockMessage(159, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11643  TemporaryDelay = true;
11644  Utilities->CallLogPop(2661); //may be able to split further back but leave as is to avoid complication
11645  return(true);
11646  }
11647  if(OtherTrainOnTrack(6, FwdPos[1], FwdPos1EntryPos, TrainID))
11648  {
11649  TrainController->StopTTClockMessage(160, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11650  TemporaryDelay = true;
11651  Utilities->CallLogPop(2662); //may be able to split further back but leave as is to avoid complication
11652  return(true);
11653  }
11654  if(OtherTrainOnTrack(7, FwdPos[2], FwdPos2ExitPos, TrainID))
11655  {
11656  TrainController->StopTTClockMessage(161, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11657  TemporaryDelay = true;
11658  Utilities->CallLogPop(2663); //may be able to split further back but leave as is to avoid complication
11659  return(true);
11660  }
11661  Utilities->CallLogPop(2664);
11662  return(true);
11663  }
11664 
11665  else if((NumFwdNamedElements == 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11666  { //Front train moves onto the 1 forward named element & rear train occupies 1 element behind original train - M L - >> RM RL FM FL
11667  FrontTrainFrontPos = FwdPos[1];
11668  FrontTrainRearPos = LeadElement;
11669  RearTrainFrontPos = MidElement;
11670  RearTrainRearPos = RwdPos[1];
11671  if(FwdDerail1)
11672  {
11673  TrainController->StopTTClockMessage(162, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11674  TemporaryDelay = true;
11675  Utilities->CallLogPop(2665); //may be able to split further back but leave as is to avoid complication
11676  return(true);
11677  }
11678  if(RwdDerail1)
11679  {
11680  TrainController->StopTTClockMessage(163, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11681  TemporaryDelay = true;
11682  Utilities->CallLogPop(2666); //may be able to split further back but leave as is to avoid complication
11683  return(true);
11684  }
11685  if(OtherTrainOnTrack(8, FwdPos[1], FwdPos1EntryPos, TrainID))
11686  {
11687  TrainController->StopTTClockMessage(164, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11688  TemporaryDelay = true;
11689  Utilities->CallLogPop(2667); //may be able to split further back but leave as is to avoid complication
11690  return(true);
11691  }
11692  if(OtherTrainOnTrack(9, RwdPos[1], RwdPos1ExitPos, TrainID))
11693  {
11694  TrainController->StopTTClockMessage(165, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11695  TemporaryDelay = true;
11696  Utilities->CallLogPop(2668); //may be able to split further back but leave as is to avoid complication
11697  return(true);
11698  }
11699  Utilities->CallLogPop(2669);
11700  return(true);
11701  }
11702 
11703  else if((NumRwdNamedElements >= 2) && (NumRwdElements == 3)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11704  {//front train occupies original train position and rear train fits behind it - - M L >> RM RL FM FL
11705  FrontTrainFrontPos = LeadElement;
11706  FrontTrainRearPos = MidElement;
11707  RearTrainFrontPos = RwdPos[1];
11708  RearTrainRearPos = RwdPos[2];
11709  if(RwdDerail1 || RwdDerail2)
11710  {
11711  TrainController->StopTTClockMessage(166, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11712  TemporaryDelay = true;
11713  Utilities->CallLogPop(2670); //may be able to split further back but leave as is to avoid complication
11714  return(true);
11715  }
11716  if(OtherTrainOnTrack(10, RwdPos[1], RwdPos1ExitPos, TrainID))
11717  {
11718  TrainController->StopTTClockMessage(167, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11719  TemporaryDelay = true;
11720  Utilities->CallLogPop(2671); //may be able to split further back but leave as is to avoid complication
11721  return(true);
11722  }
11723  if(OtherTrainOnTrack(11, RwdPos[2], RwdPos2EntryPos, TrainID))
11724  {
11725  TrainController->StopTTClockMessage(168, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11726  TemporaryDelay = true;
11727  Utilities->CallLogPop(2672); //may be able to split further back but leave as is to avoid complication
11728  return(true);
11729  }
11730  Utilities->CallLogPop(2673);
11731  return(true);
11732  }
11733 
11734 //here look for front overhang situations
11735  else if((NumFwdNamedElements == 1) && (NumFwdElements == 2)) // X N N X (N = named, X = named or not but connected)
11736  { // M L - - >> RM RL FM FL
11737  FrontTrainFrontPos = FwdPos[2];
11738  FrontTrainRearPos = FwdPos[1];
11739  RearTrainFrontPos = LeadElement;
11740  RearTrainRearPos = MidElement;
11741  if(FwdDerail1 || FwdDerail2)
11742  {
11743  TrainController->StopTTClockMessage(169, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11744  TemporaryDelay = true;
11745  Utilities->CallLogPop(2674); //may be able to split further back but leave as is to avoid complication
11746  return(true);
11747  }
11748  if(OtherTrainOnTrack(12, FwdPos[1], FwdPos1EntryPos, TrainID))
11749  {
11750  TrainController->StopTTClockMessage(170, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11751  TemporaryDelay = true;
11752  Utilities->CallLogPop(2675); //may be able to split further back but leave as is to avoid complication
11753  return(true);
11754  }
11755  if(OtherTrainOnTrack(13, FwdPos[2], FwdPos2ExitPos, TrainID))
11756  {
11757  TrainController->StopTTClockMessage(171, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11758  TemporaryDelay = true;
11759  Utilities->CallLogPop(2676); //may be able to split further back but leave as is to avoid complication
11760  return(true);
11761  }
11762  Utilities->CallLogPop(2677);
11763  return(true);
11764  }
11765 
11766  else if((NumFwdElements >= 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) // X N N X (N = named, X = named or not but connected)
11767  { // - M L - >> RM RL FM FL
11768  FrontTrainFrontPos = FwdPos[1];
11769  FrontTrainRearPos = LeadElement;
11770  RearTrainFrontPos = MidElement;
11771  RearTrainRearPos = RwdPos[1];
11772  if(FwdDerail1)
11773  {
11774  TrainController->StopTTClockMessage(172, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11775  TemporaryDelay = true;
11776  Utilities->CallLogPop(2678); //may be able to split further back but leave as is to avoid complication
11777  return(true);
11778  }
11779  if(RwdDerail1)
11780  {
11781  TrainController->StopTTClockMessage(173, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11782  TemporaryDelay = true;
11783  Utilities->CallLogPop(2679); //may be able to split further back but leave as is to avoid complication
11784  return(true);
11785  }
11786  if(OtherTrainOnTrack(14, FwdPos[1], FwdPos1EntryPos, TrainID))
11787  {
11788  TrainController->StopTTClockMessage(174, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11789  TemporaryDelay = true;
11790  Utilities->CallLogPop(2680); //may be able to split further back but leave as is to avoid complication
11791  return(true);
11792  }
11793  if(OtherTrainOnTrack(15, RwdPos[1], RwdPos1ExitPos, TrainID))
11794  {
11795  TrainController->StopTTClockMessage(175, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11796  TemporaryDelay = true;
11797  Utilities->CallLogPop(2681); //may be able to split further back but leave as is to avoid complication
11798  return(true);
11799  }
11800  Utilities->CallLogPop(2682);
11801  return(true);
11802  }
11803 //anything else fails as location too short
11804  Utilities->CallLogPop(2652);
11805  return(false);
11806 }
11807 
11808 // ---------------------------------------------------------------------------
11809 
11810 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
11811 {
11812  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
11813  TLocationNameMultiMapIterator SNIterator;
11814  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11815 
11816  if(SNRange.first != SNRange.second)
11817  {
11818  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11819  {
11820  if(SNIterator->second < 0)
11821  {
11822  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
11823  }
11824  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
11825  SNIterator->second).TrackType == NamedNonStationLocation))
11826  {
11827  Utilities->CallLogPop(1121);
11828  return(true);
11829  }
11830  }
11831  }
11832  Utilities->CallLogPop(848);
11833  return(false);
11834 }
11835 
11836 // ---------------------------------------------------------------------------
11837 
11838 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11839 {
11840 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11841  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11842  "," + AnsiString(SpeedTag));
11843  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11844  {
11845  Utilities->CallLogPop(949);
11846  return(false);
11847  }
11848  bool FoundFlag;
11849  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11850 
11851  if(!FoundFlag)
11852  {
11853  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11854  }
11855  TTrackElement IAElement;
11856 
11857  if(SpeedTag == 68) // top sig
11858  {
11859  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11860  {
11861  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11862  {
11863  IAElement = InactiveTrackElementAt(50, IMPair.first);
11864  }
11865  else
11866  {
11867  IAElement = InactiveTrackElementAt(51, IMPair.second);
11868  }
11869  if(IAElement.LocationName == "")
11870  {
11871 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11872  SignalPlatformGraphic = RailGraphics->gl76Striped;
11873  }
11874  else
11875  {
11876 // SignalPlatformGraphic = RailGraphics->Plat68;
11877  SignalPlatformGraphic = RailGraphics->gl76;
11878  }
11879  Utilities->CallLogPop(950);
11880  return(true);
11881  }
11882  }
11883  else if(SpeedTag == 69) // bot sig
11884  {
11885  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11886  {
11887  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11888  {
11889  IAElement = InactiveTrackElementAt(77, IMPair.first);
11890  }
11891  else
11892  {
11893  IAElement = InactiveTrackElementAt(78, IMPair.second);
11894  }
11895  if(IAElement.LocationName == "")
11896  {
11897 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11898  SignalPlatformGraphic = RailGraphics->bm77Striped;
11899  }
11900  else
11901  {
11902 // SignalPlatformGraphic = RailGraphics->Plat69;
11903  SignalPlatformGraphic = RailGraphics->bm77;
11904  }
11905  Utilities->CallLogPop(951);
11906  return(true);
11907  }
11908  }
11909  else if(SpeedTag == 70) // left sig
11910  {
11911  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11912  {
11913  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11914  {
11915  IAElement = InactiveTrackElementAt(55, IMPair.first);
11916  }
11917  else
11918  {
11919  IAElement = InactiveTrackElementAt(82, IMPair.second);
11920  }
11921  if(IAElement.LocationName == "")
11922  {
11923 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11924  SignalPlatformGraphic = RailGraphics->bm78Striped;
11925  }
11926  else
11927  {
11928 // SignalPlatformGraphic = RailGraphics->Plat70;
11929  SignalPlatformGraphic = RailGraphics->bm78;
11930  }
11931  Utilities->CallLogPop(952);
11932  return(true);
11933  }
11934  }
11935  else if(SpeedTag == 71) // right sig
11936  {
11937  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11938  {
11939  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11940  {
11941  IAElement = InactiveTrackElementAt(85, IMPair.first);
11942  }
11943  else
11944  {
11945  IAElement = InactiveTrackElementAt(86, IMPair.second);
11946  }
11947  if(IAElement.LocationName == "")
11948  {
11949 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11950  SignalPlatformGraphic = RailGraphics->gl79Striped;
11951  }
11952  else
11953  {
11954 // SignalPlatformGraphic = RailGraphics->Plat71;
11955  SignalPlatformGraphic = RailGraphics->gl79;
11956  }
11957  Utilities->CallLogPop(953);
11958  return(true);
11959  }
11960  }
11961  Utilities->CallLogPop(954);
11962  return(false);
11963 }
11964 
11965 // ---------------------------------------------------------------------------
11966 
11967 bool TTrack::OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
11968 // returns true if another train on LinkPos track of element at TrackPos, whether bridge or not, return false if not, or if TrackPos == -1,
11969 // or LinkPos == -1, or if only own train on the track. LinkPos can be entry or exit.
11970 {
11971  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(TrackPos) + "," +
11972  AnsiString(LinkPos) + "," + AnsiString(OwnTrainID));
11973  if((LinkPos < 0) || (TrackPos < 0))
11974  {
11975  Utilities->CallLogPop(1348);
11976  return(false);
11977  }
11978  TTrackElement TrackElement = TrackElementAt(713, TrackPos);
11979 
11980  if(TrackElement.TrackType != Bridge)
11981  {
11982  Utilities->CallLogPop(1349);
11983  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11984  }
11985 // bridge if reach here
11986  if(LinkPos > 1)
11987  {
11988  Utilities->CallLogPop(1350);
11989  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11990  }
11991  else
11992  {
11993  Utilities->CallLogPop(1351);
11994  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11995  }
11996 }
11997 
11998 // ---------------------------------------------------------------------------
11999 
12001 {
12002  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
12003  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
12004  {
12005  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
12006  }
12007  Utilities->CallLogPop(1483);
12008  return(SelectVector.at(At));
12009 }
12010 
12011 // ---------------------------------------------------------------------------
12012 
12013 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
12014 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
12015 {
12016  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
12017  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
12018  bool FoundFlag = false;
12019  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
12020  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
12021 
12022  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
12023  Utilities->CallLogPop(1538);
12024  return(FoundFlag);
12025 }
12026 
12027 // ---------------------------------------------------------------------------
12028 
12029 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
12030 {
12031 // return true if find an inactive element called 'Name'
12032  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
12033  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
12034  bool FoundFlag = false;
12035 
12036  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
12037  {
12038  if(InactiveTrackElementAt(158, x).LocationName == Name)
12039  {
12040  FoundFlag = true;
12041  int V = InactiveTrackElementAt(159, x).VLoc;
12042  int H = InactiveTrackElementAt(160, x).HLoc;
12043  if(V > VLocHi)
12044  {
12045  VLocHi = V;
12046  }
12047  if(V < VLocLo)
12048  {
12049  VLocLo = V;
12050  }
12051  if(H < HLoc)
12052  {
12053  HLoc = H;
12054  }
12055  }
12056  }
12057  if(FoundFlag)
12058  {
12059  VPosHi = 16 * VLocHi;
12060  VPosLo = 16 * VLocLo;
12061  HPos = 16 * HLoc;
12062  Utilities->CallLogPop(1562);
12063  return(true);
12064  }
12065  else
12066  {
12067  Utilities->CallLogPop(1563);
12068  return(false);
12069  }
12070 }
12071 
12072 // ---------------------------------------------------------------------------
12073 
12074 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
12075 {
12076 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
12077 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
12078  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
12079  AnsiString(EndTVPosition));
12080  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
12081  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
12082 
12083 // get H & V values for the element adjacent to Link[0] & Link[1]
12084  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
12085  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
12086  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
12087  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
12088 
12089 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
12090  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
12091  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
12092  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
12093  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
12094 
12095  if(Link0Squares <= Link1Squares)
12096  {
12097  Utilities->CallLogPop(1851);
12098  return(0);
12099  }
12100  else
12101  {
12102  Utilities->CallLogPop(1852);
12103  return(1);
12104  }
12105 }
12106 
12107 // ---------------------------------------------------------------------------
12108 
12109 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
12110 {
12111  // element can be points or any other type
12112  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
12113  AnsiString(LinkPos));
12114  Derail = false;
12115  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
12116 
12117  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
12118  {
12119  if(TE.Attribute == 0)
12120  {
12121  Utilities->CallLogPop(663);
12122  return(1); // Att == 0 & ExitPos == 1 represent straight
12123  }
12124  else
12125  {
12126  Utilities->CallLogPop(664);
12127  return(3); // Att == 1 & ExitPos == 3 represent diverging
12128  }
12129  }
12130  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
12131  {
12132  if((LinkPos == 1) && (TE.Attribute == 0))
12133  {
12134  Utilities->CallLogPop(665);
12135  return(0); // Att == 0 represents straight
12136  }
12137  else if(LinkPos == 1)
12138  {
12139  Derail = true;
12140  Utilities->CallLogPop(666);
12141  return(0);
12142  }
12143  else if((LinkPos == 3) && (TE.Attribute == 1))
12144  {
12145  Utilities->CallLogPop(667);
12146  return(0);
12147  }
12148  else if(LinkPos == 3)
12149  {
12150  Derail = true;
12151  Utilities->CallLogPop(668);
12152  return(0);
12153  }
12154  }
12155  else if(LinkPos == 0)
12156  {
12157  Utilities->CallLogPop(669);
12158  return(1);
12159  }
12160  else if(LinkPos == 1)
12161  {
12162  Utilities->CallLogPop(670);
12163  return(0);
12164  }
12165  else if(LinkPos == 2)
12166  {
12167  Utilities->CallLogPop(671);
12168  return(3);
12169  }
12170  else if(LinkPos == 3)
12171  {
12172  Utilities->CallLogPop(672);
12173  return(2);
12174  }
12175  throw Exception("Error, failure in GetExitPos"); // should never reach here
12176 }
12177 
12178 // ----------------------------------------------------------------------------
12179 
12181 {
12182  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
12183  LCVector.clear();
12184  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
12185  {
12186  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
12187  {
12188  LCVector.push_back(x);
12189  }
12190  }
12191  Utilities->CallLogPop(1931);
12192  return;
12193 }
12194 
12195 // ---------------------------------------------------------------------------
12196 
12197 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
12198 /*
12199  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
12200  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
12201  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
12202  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
12203 */
12204 {
12205  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
12206  AnsiString(Link));
12207  bool FoundFlag;
12208 
12209  TrainID = -1;
12210  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
12211 
12212  if(!FoundFlag)
12213  {
12214  Utilities->CallLogPop(2001);
12215  return(false);
12216  }
12217  TTrackElement TE = TrackElementAt(882, VecPos);
12218 
12219  TrainID = TE.TrainIDOnElement;
12220  if(TE.TrackType == Bridge)
12221  {
12222  if(TE.TrainIDOnElement > -1)
12223  {
12224  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
12225  {
12227  }
12228  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
12229  {
12231  }
12232  else
12233  {
12234  TrainID = -1; // shouldn't ever reach here but be safe
12235  }
12236  }
12237  }
12238  if(TrainID == -1)
12239  {
12240  Utilities->CallLogPop(2002);
12241  return(false);
12242  }
12243 // now get the train
12244  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
12245 
12246  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
12247  {
12248  Utilities->CallLogPop(2003);
12249  return(true);
12250  }
12251  TrainID = -1;
12252  Utilities->CallLogPop(2004);
12253  return(false);
12254 }
12255 
12256 // ---------------------------------------------------------------------------
12257 
12258 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
12259 /* New at v1.2.0
12260  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
12261  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
12262  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12263  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12264  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12265  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12266  Each of these is examined in turn for each route element in the relevant position.
12267 */
12268 {
12269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
12270  "," + AnsiString(DiagonalLinkNumber));
12271  TrainID = -1;
12272  TPrefDirElement TempPrefDirElement;
12273  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
12274 
12275  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
12276  {
12277  Utilities->CallLogPop(2027);
12278  return(true);
12279  }
12280  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
12281  {
12282  Utilities->CallLogPop(2028);
12283  return(true);
12284  }
12285  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
12286  {
12287  Utilities->CallLogPop(2029);
12288  return(true);
12289  }
12290  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
12291  {
12292  Utilities->CallLogPop(2030);
12293  return(true);
12294  }
12295  Utilities->CallLogPop(2031);
12296  return(false);
12297 }
12298 
12299 // ---------------------------------------------------------------------------
12300 
12301 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
12302 {
12303  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
12304  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
12305  TUserGraphicItem UGI;
12306  AnsiString JustFileName = "";
12307 
12308  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
12309  {
12310  UGI = UserGraphicVectorAt(17, x);
12311  int LastDelim = UGI.FileName.LastDelimiter('\\');
12312  if(LastDelim == 0) // can't find it so skip this item
12313  {
12314  continue;
12315  }
12316  else
12317  {
12318  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
12319  }
12320  Utilities->SaveFileString(VecFile, JustFileName);
12321  Utilities->SaveFileInt(VecFile, UGI.HPos);
12322  Utilities->SaveFileInt(VecFile, UGI.VPos);
12323  }
12324  Utilities->CallLogPop(2178);
12325 }
12326 
12327 // ---------------------------------------------------------------------------
12328 
12329 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
12330 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
12331 {
12332  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
12333  int NumPlats = 0;
12334  TTrackElement TempElement;
12335  int TempInt;
12336 
12337  typedef std::list<int> TNamePosList;
12338  TNamePosList NamePosList;
12339  typedef TNamePosList::iterator TNPLIt;
12340  TNPLIt NPLIt;
12341  typedef std::list<int> TOnePlatList;
12342  TOnePlatList OnePlatList;
12343  typedef TOnePlatList::iterator TOPLIt;
12344  TOPLIt OPLIt;
12345 
12346  NamePosList.clear();
12347  OnePlatList.clear();
12348  for(unsigned int x = 0; x < TrackVector.size(); x++)
12349  {
12350  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
12351  {
12352  NamePosList.push_back(x);
12353  }
12354  }
12355  //NamePosList complete
12356 
12357  if(!NamePosList.empty()) //first value for the loop examination
12358  {
12359  OnePlatList.push_back(NamePosList.back());
12360  NamePosList.pop_back(); //erase from NPV as done with it here
12361  }
12362  while(!OnePlatList.empty()) //loop to examine all linked elements
12363  {
12364  TempInt = OnePlatList.front();
12365  TempElement = TrackElementAt(989, TempInt);
12366 
12367  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
12368  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
12369  {
12370  OnePlatList.push_back(TempElement.Conn[0]);
12371  NamePosList.erase(NPLIt);
12372  }
12373  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
12374  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
12375  {
12376  OnePlatList.push_back(TempElement.Conn[1]);
12377  NamePosList.erase(NPLIt);
12378  }
12379  //here when loaded any connecting links into OnePlatList, so can erase the front element
12380  OnePlatList.erase(OnePlatList.begin());
12381  if(OnePlatList.empty())
12382  {
12383  NumPlats++; //finished with current linked elements so can increment NumPlats
12384  if(!NamePosList.empty())
12385  {
12386  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
12387  NamePosList.pop_back(); //erase from NPV as done with it there
12388  }
12389  }
12390  }
12391  Utilities->CallLogPop(2218);
12392  return(NumPlats);
12393 }
12394 
12395 // ---------------------------------------------------------------------------
12396 
12397 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12398 {//repair Signals pointed to by FPVIt
12399  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
12400  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
12401  if(TE.TrackType != SignalPost)
12402  {
12403  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
12404  }
12405  if(!TE.Failed)
12406  {
12407  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
12408  }
12409  TE.Failed = false;
12410  //set to correct aspect
12411  int RouteNumber;
12412  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
12413  { // 0 for LinkPos ok as a signal so only one track
12414  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
12415  }
12416  //erase from vector
12417  Track->FailedSignalsVector.erase(FPVIt);
12418 
12419  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12420  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12421  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
12422  AllRoutes->RebuildRailwayFlag = true;
12423  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
12424  Utilities->CallLogPop(2519);
12425 }
12426 
12427 // ---------------------------------------------------------------------------
12428 
12429 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12430 {//repair points pointed to by FPVIt
12431  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
12432  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
12433  if(TE.TrackType != Points)
12434  {
12435  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
12436  }
12437  if(!TE.Failed)
12438  {
12439  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
12440  }
12441  TE.Failed = false;
12446  //erase from vector
12447  Track->FailedPointsVector.erase(FPVIt);
12448 
12449  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12450  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12451  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
12452  AllRoutes->RebuildRailwayFlag = true;
12453  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12454  Utilities->CallLogPop(2518);
12455 }
12456 
12457 // ---------------------------------------------------------------------------
12458 
12459 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12460 {//repair TSR pointed to by FPVIt
12461  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
12462  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
12463  if(TE.TrackType != Simple)
12464  {
12465  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
12466  }
12467  if(!TE.Failed)
12468  {
12469  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
12470  }
12471  TE.Failed = false;
12474  //erase from vector
12475  Track->TSRVector.erase(FPVIt);
12476 
12477  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12478  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12479  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
12480  AllRoutes->RebuildRailwayFlag = true;
12481  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12482  Utilities->CallLogPop(2520);
12483 }
12484 
12485 // ---------------------------------------------------------------------------
12486 
12488 {
12489  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
12490  SimpleVector.clear();
12491  for(unsigned int x = 0; x < TrackVector.size(); x++)
12492  {
12493  if(TrackElementAt(1517, x).TrackType == Simple)
12494  {
12495  SimpleVector.push_back(int(x));
12496  }
12497  }
12498  Utilities->CallLogPop(2521);
12499 }
12500 
12501 // ---------------------------------------------------------------------------
12502 // UserGraphic, PrefDir & Route functions
12503 // ---------------------------------------------------------------------------
12504 
12506 {
12507  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
12508  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
12509  {
12510  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
12511  }
12512  Utilities->CallLogPop(2194);
12513  return(UserGraphicVector.at(At));
12514 }
12515 
12516 // ---------------------------------------------------------------------------
12517 
12518 int TOnePrefDir::LastElementNumber(int Caller) const
12519 {
12520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
12521  int RetVal = PrefDirVector.size() - 1;
12522 
12523  if(RetVal < 0)
12524  {
12525  throw Exception("Return value negative in call to LastElementNumber");
12526  }
12527  Utilities->CallLogPop(114);
12528  return(RetVal);
12529 }
12530 
12531 // ---------------------------------------------------------------------------
12533 {
12534  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
12535  if(PrefDirVector.empty())
12536  {
12537  throw Exception("PrefDirVector empty in call to LastElementPtr");
12538  }
12539  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
12540 
12541  Utilities->CallLogPop(115);
12542  return(RetIT);
12543 }
12544 
12545 // ---------------------------------------------------------------------------
12547 {
12548  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
12549  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12550  {
12551  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
12552  }
12553  Utilities->CallLogPop(116);
12554  return(PrefDirVector.at(At));
12555 }
12556 
12557 // ---------------------------------------------------------------------------
12559 {
12560  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
12561  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12562  {
12563  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
12564  " in GetModifiablePrefDirElementAt");
12565  }
12566  Utilities->CallLogPop(117);
12567  return(PrefDirVector.at(At));
12568 }
12569 
12570 // ---------------------------------------------------------------------------
12572 {
12573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
12574  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12575  {
12576  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
12577  }
12578  Utilities->CallLogPop(118);
12579  return(SearchVector.at(At));
12580 }
12581 
12582 // ---------------------------------------------------------------------------
12584 {
12585  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
12586  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12587  {
12588  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
12589  }
12590  Utilities->CallLogPop(119);
12591  return(SearchVector.at(At));
12592 }
12593 
12594 // ---------------------------------------------------------------------------
12595 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
12596 /*
12597  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
12598  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
12599  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
12600  set in later functions.
12601 */
12602 {
12603  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12604  ClearPrefDir();
12605  int TrackVectorPosition;
12606  TTrackElement TrackElement;
12607 
12608  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12609  {
12610  Utilities->CallLogPop(126);
12611  return(false);
12612  }
12613 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
12614  if(TrackElement.TrackType == Points)
12615  {
12616  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
12617  //it isn't known which trailing edge is the required PrefDir - could use the straight as
12618  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
12619  //best to prevent it to avoid problems
12620  Utilities->CallLogPop(127);
12621  return false;
12622  }
12623 */
12624  TPrefDirElement PrefDirElement(TrackElement);
12625 
12626  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
12627  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
12628  StorePrefDirElement(1, PrefDirElement); // enter first element
12629 // Note that ELink not set even if a buffer or continuation - these set in
12630 // ConvertPrefDirSearchVector after 2nd element added
12631 
12632  Utilities->CallLogPop(128);
12633  return(true);
12634 }
12635 
12636 // ---------------------------------------------------------------------------
12637 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
12638 
12639 /*
12640  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
12641  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
12642  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
12643  with setting the PrefDir vector, & return true.
12644  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
12645  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
12646  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
12647  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
12648  ConvertPrefDirSearchVector to set PrefDirVector.
12649  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
12650  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
12651  find the required element return false. CheckCount is used to keep track of set values to allow check later.
12652 */
12653 
12654 {
12655  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12656  FinishElement = false;
12657  int TrackVectorPosition;
12658 
12659  TotalSearchCount = 0;
12660  TTrackElement TrackElement, TempTrackElement;
12661 
12662  if(PrefDirVector.size() == 0)
12663  {
12664  Utilities->CallLogPop(129);
12665  return(false);
12666  }
12667  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12668  {
12669  Utilities->CallLogPop(130);
12670  return(false);
12671  }
12672 // set the search limits using the last stored element in PrefDirVector as the start point
12673 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12674 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12675 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12676 
12677  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
12678 
12679  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
12680  {
12681  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
12682  SearchLimitHighH = TrackElement.HLoc + 15;
12683  }
12684  else
12685  {
12686  SearchLimitLowH = TrackElement.HLoc - 15;
12687  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
12688  }
12689  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
12690  {
12691  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
12692  SearchLimitHighV = TrackElement.VLoc + 15;
12693  }
12694  else
12695  {
12696  SearchLimitLowV = TrackElement.VLoc - 15;
12697  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
12698  }
12699 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
12700  check & TotalSearchCounts check
12701  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
12702  {
12703  ShowMessage("Unable to reach the selected element - too far ahead");
12704  Utilities->CallLogPop(1692);
12705  return false;
12706  }
12707 */
12708 // get last PrefDir element
12709  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
12710  {
12711  // check if TrackElement adjacent to any of the 4 XLinkPos'
12712  for(int x = 0; x < 4; x++)
12713  {
12714  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
12715  {
12716  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
12717  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
12718  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
12719  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
12720  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
12721  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
12722  // shouldn't ever get it in a serious railway though.
12723 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
12724  }
12725  }
12726  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
12727  {
12728  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
12729  SearchVector.clear(); // use this & convert to set all PrefDir element values
12730  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
12731  {
12733  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12734  {
12735  FinishElement = true;
12736  }
12737  Utilities->CallLogPop(131);
12738  return(true);
12739  }
12740  } // not an adjacent element
12741 
12742  // now check each of the 4 possible XLinkPos values
12743  for(int x = 0; x < 4; x++)
12744  {
12745  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
12746  {
12747  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
12748  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
12749  SearchVector.clear();
12750  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
12751  {
12753  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12754  {
12755  FinishElement = true;
12756  }
12757  Utilities->CallLogPop(132);
12758  return(true);
12759  }
12760  }
12761  } // here if checked all possible exits without success
12762  ShowMessage(
12763  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12764  Utilities->CallLogPop(133);
12765  return(false);
12766  }
12767 // dealt above with LastPrefDirElement being the start element (which can be points)
12768 
12769  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
12770  .ELinkPos] == Lead)) // leading point
12771  {
12772  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
12773  {
12774  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
12775  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
12776  // can't be buffers or gap if points
12777  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
12778  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
12779  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
12780  SearchVector.clear();
12781  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
12782  {
12784  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12785  {
12786  FinishElement = true;
12787  }
12788  Utilities->CallLogPop(134);
12789  return(true);
12790  }
12791  }
12792  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
12793  {
12794  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
12795  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
12796  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
12797  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
12798  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
12799  SearchVector.clear();
12800  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
12801  {
12803  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12804  {
12805  FinishElement = true;
12806  }
12807  Utilities->CallLogPop(135);
12808  return(true);
12809  }
12810  }
12811 // above dealt with immediate finds for leading point,
12812 // now deal with ordinary searches for leading point
12813  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
12814  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
12815  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
12816  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
12817  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
12818  SearchVector.clear();
12819  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
12820  {
12822  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12823  {
12824  FinishElement = true;
12825  }
12826  Utilities->CallLogPop(136);
12827  return(true);
12828  }
12829  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
12830  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12831  // note that CheckCount already increased to allow for XLinkPos & XLink
12832  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12833  SearchVector.clear();
12834  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12835  {
12837  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12838  {
12839  FinishElement = true;
12840  }
12841  Utilities->CallLogPop(137);
12842  return(true);
12843  }
12844 // here if failed to find match for leading point
12845  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12846  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12847  ShowMessage(
12848  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12849  Utilities->CallLogPop(138);
12850  return(false);
12851  }
12852 // leading point fully dealt with above
12853 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12854 // separately as covered in ordinary search.
12855 
12856  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12857  SearchVector.clear();
12858 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12859  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12860  {
12862  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12863  {
12864  FinishElement = true;
12865  }
12866  Utilities->CallLogPop(139);
12867  return(true);
12868  }
12869  ShowMessage(
12870  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12871  Utilities->CallLogPop(140);
12872  return(false); // failed to find required element
12873 }
12874 
12875 // ---------------------------------------------------------------------------
12876 
12877 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12878 /*
12879  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12880  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12881  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12882  Keep a count of entries in SearchVector during the current function call, so that this number can be
12883  erased for an unproductive branch search.
12884  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12885  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12886  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12887  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12888  If not any of above, store element in searchvector, set the new current element values from the
12889  SearchElement, then go back to the while loop for the next step in the search.
12890 */
12891 {
12892  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12893  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12894  int VectorCount = 0;
12895 
12896  while(true)
12897  {
12898  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12899  {
12900  for(int x = 0; x < VectorCount; x++)
12901  {
12902  SearchVector.erase(SearchVector.end() - 1);
12903  }
12904  Utilities->CallLogPop(141);
12905  return(false);
12906  }
12907  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12908  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12909  TPrefDirElement SearchElement(NextTrackElement);
12910  SearchElement.TrackVectorPosition = NextPosition;
12911  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12912  SearchElement.ELinkPos = NextELinkPos;
12913  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12914  int NextXLinkPos;
12915  if(SearchElement.ELinkPos == 0)
12916  {
12917  NextXLinkPos = 1;
12918  }
12919  if(SearchElement.ELinkPos == 1)
12920  {
12921  NextXLinkPos = 0;
12922  }
12923  if(SearchElement.ELinkPos == 2)
12924  {
12925  NextXLinkPos = 3;
12926  }
12927  if(SearchElement.ELinkPos == 3)
12928  {
12929  NextXLinkPos = 2;
12930  }
12931  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12932  {
12933  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12934  // but may be buffers, continuation or gap
12935  SearchElement.XLinkPos = NextXLinkPos;
12936  }
12937 // can't set XLink or XLinkPos yet if the element is a leading point.
12938 // check if found it
12939  if(SearchElement.TrackVectorPosition == RequiredPosition)
12940  {
12941  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12942  VectorCount++; // not really needed but include for tidyness
12943  TotalSearchCount++;
12944  Utilities->CallLogPop(142);
12945  return(true);
12946  }
12947 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12948 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12949 // at a time - drop this
12950 /*
12951  if(PrefDirVector.size() > 200)
12952  {
12953  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12954  Utilities->CallLogPop(1419);
12955  return false;
12956  }
12957 */
12958 // check if a buffer or continuation
12959  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12960  {
12961  for(int x = 0; x < VectorCount; x++)
12962  {
12963  SearchVector.erase(SearchVector.end() - 1);
12964  }
12965  Utilities->CallLogPop(143);
12966  return(false);
12967  }
12968 // check if reached an earlier position on search PrefDir with same entry value
12969  for(unsigned int x = 0; x < SearchVector.size(); x++)
12970  {
12971  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12972  {
12973  for(int x = 0; x < VectorCount; x++)
12974  {
12975  SearchVector.erase(SearchVector.end() - 1);
12976  }
12977  Utilities->CallLogPop(144);
12978  return(false);
12979  }
12980  }
12981 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12982 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12983  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12984  {
12985  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12986  {
12987  for(int x = 0; x < VectorCount; x++)
12988  {
12989  SearchVector.erase(SearchVector.end() - 1);
12990  }
12991  Utilities->CallLogPop(1417);
12992  return(false);
12993  }
12994  }
12995 
12996 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12997 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12998 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13000  {
13001  for(int x = 0; x < VectorCount; x++)
13002  {
13003  SearchVector.erase(SearchVector.end() - 1);
13004  }
13005  Utilities->CallLogPop(1691);
13006  return(false);
13007  }
13008 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
13009  if(SearchVector.size() > 150)
13010  {
13011  for(int x = 0; x < VectorCount; x++)
13012  {
13013  SearchVector.erase(SearchVector.end() - 1);
13014  }
13015  Utilities->CallLogPop(1418);
13016  return(false);
13017  }
13018 // check if reached a leading point
13019  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13020  {
13021 // push element with XLink set to position [1]
13022  SearchElement.XLink = SearchElement.Link[1];
13023  SearchElement.XLinkPos = 1;
13024  SearchVector.push_back(SearchElement);
13025  VectorCount++;
13026  TotalSearchCount++;
13027  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
13028  // Note that have to use a TTrackElement in the recursive search, so SearchElement
13029  // can't be used. NextTrackElement is the corresponding TTrackElement.
13030  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
13031  {
13032  Utilities->CallLogPop(145);
13033  return(true);
13034  }
13035  else
13036  {
13037 // remove leading point with XLinkPos [1]
13038  SearchVector.erase(SearchVector.end() - 1);
13039  VectorCount--;
13040 // push element with XLink set to position [3]
13041  SearchElement.XLink = SearchElement.Link[3];
13042  SearchElement.XLinkPos = 3;
13043  SearchVector.push_back(SearchElement);
13044  VectorCount++;
13045  TotalSearchCount++;
13046 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
13047  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
13048  {
13049  Utilities->CallLogPop(146);
13050  return(true);
13051  }
13052  else
13053  {
13054  for(int x = 0; x < VectorCount; x++)
13055  {
13056  SearchVector.erase(SearchVector.end() - 1);
13057  }
13058  Utilities->CallLogPop(147);
13059  return(false);
13060  }
13061  }
13062  } // if leading point
13063 
13064 // here if ordinary element, push it, inc vector & update CurrentTrackElement
13065 // ready for next element on PrefDir
13066  SearchVector.push_back(SearchElement);
13067  VectorCount++;
13068  TotalSearchCount++;
13069  XLinkPos = NextXLinkPos;
13070  CurrentTrackElement = SearchElement;
13071  } // while(true)
13072 }
13073 
13074 // ---------------------------------------------------------------------------
13075 
13077 /*
13078  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
13079  for each element on the search PrefDir, though if the last element is a leading point
13080  then the final XLink won't be set.
13081  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
13082  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
13083  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
13084 */
13085 {
13086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
13087  if(SearchVector.size() == 0)
13088  {
13089  throw Exception("Error, SearchVector empty");
13090  }
13091 // get first SearchElement in order to set last PrefDirelement
13092  TPrefDirElement SearchElement = SearchVector.at(0);
13093 
13094 // set last PrefDir element XLink & ELink values if not already set
13095 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
13096  for(int x = 0; x < 4; x++)
13097  {
13098  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
13099  {
13100  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
13101  {
13102  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
13103  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
13104  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
13105  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
13106  }
13107  int ELinkPos;
13108  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
13109  {
13110  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
13111  }
13112  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
13113  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
13114  {
13115  ELinkPos = 0;
13116  }
13117  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
13118  {
13119  ELinkPos = 3;
13120  }
13121  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
13122  {
13123  ELinkPos = 2;
13124  }
13125  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
13126  {
13127  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
13128  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
13129  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
13130  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
13131  }
13132  break; // no point going any further
13133  }
13134  }
13135 // set EXNumber for last PrefDir element, unless already set
13136 // won't be set if was first element or a leading point
13137  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
13138  {
13139 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
13140  int EXArray[32][2] = {
13141  {4,6},{2,8}, //horizontal & vertical
13142  {2,4},{6,2},{8,6},{4,8}, //sharp curves
13143  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
13144  {1,9},{3,7} //forward & reverse diagonals
13145 */
13146 
13147  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
13148  {
13149  throw Exception("Error in EntryExitNumber 1");
13150  }
13151  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
13152  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
13153  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
13154  }
13155 // Last PrefDir element now complete
13156 
13157 // construct remaining PrefDir elements from searchvector
13158  for(unsigned int x = 0; x < SearchVector.size(); x++)
13159  {
13160  SearchElement = SearchVector.at(x);
13161  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
13162  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
13163  PrefDirElement.ELink = SearchElement.ELink;
13164  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
13165  PrefDirElement.XLink = SearchElement.XLink;
13166  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
13167 // if XLink & XLinkPos not set don't account for them in CheckCount
13168  if(PrefDirElement.XLink == -1)
13169  {
13170  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
13171  }
13172  // & TrackVectorPosition
13173  else
13174  {
13175  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
13176  }
13177  // XLink, XLinkPos, TrackVectorPosition
13178 
13179 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
13180  if(PrefDirElement.XLink != -1)
13181  {
13182  if(!(PrefDirElement.EntryExitNumber()))
13183  {
13184  throw Exception("Error in EntryExitNumber 2");
13185  }
13186  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
13187  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
13188  PrefDirElement.CheckCount++;
13189  // all values now incorporated if not a leading point
13190  }
13191 // store PrefDir element
13192  StorePrefDirElement(2, PrefDirElement);
13193  }
13194 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
13195  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
13196  {
13197  if(ValidatePrefDir(2))
13198  {
13199  ;
13200  } // error messages given within function
13201 
13202  }
13204 /* drop this, check dropped from search
13205  if(PrefDirVector.size() > 200)
13206  {
13207  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
13208  }
13209 */
13210  Utilities->CallLogPop(148);
13211 }
13212 
13213 // ---------------------------------------------------------------------------
13214 
13215 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
13216 /*
13217  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
13218  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
13219 */
13220 {
13221  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
13222  LeadingPoints = false;
13223  if(PrefDirVector.empty())
13224  {
13225  Utilities->CallLogPop(1786);
13226  return(false); // should never be empty but allow for it for safety
13227  }
13228  if(PrefDirVector.size() == 1)
13229  {
13230  Utilities->CallLogPop(149);
13231  return(false); // can't end if only one element
13232  }
13233 /*
13234  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
13235  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
13236  {
13237  Utilities->CallLogPop(150);
13238  return true;
13239  }
13240 */
13241 // allow for anything but leading points
13242  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
13243  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
13244  {
13245  Utilities->CallLogPop(1776);
13246  return(true);
13247  }
13248  else
13249  {
13250  LeadingPoints = true;
13251  Utilities->CallLogPop(151);
13252  return(false);
13253  }
13254 }
13255 
13256 // ---------------------------------------------------------------------------
13257 
13259 /*
13260  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
13261  and that every element is connected to the next element
13262 */
13263 {
13264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
13265  int Position;
13266  AnsiString ErrorString;
13267  bool Error = false;
13268 
13269  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13270  {
13271  if(PrefDirVector.at(x).HLoc == -2000000000)
13272  {
13273  Error = true;
13274  ErrorString = "HLoc";
13275  Position = x;
13276  }
13277  if(PrefDirVector.at(x).VLoc == -2000000000)
13278  {
13279  Error = true;
13280  ErrorString = "VLoc";
13281  Position = x;
13282  }
13283  if(PrefDirVector.at(x).ELink == -1)
13284  {
13285  Error = true;
13286  ErrorString = "ELink";
13287  Position = x;
13288  }
13289  if(PrefDirVector.at(x).ELinkPos == -1)
13290  {
13291  Error = true;
13292  ErrorString = "ELinkPos";
13293  Position = x;
13294  }
13295  if(PrefDirVector.at(x).XLink == -1)
13296  {
13297  Error = true;
13298  ErrorString = "XLink";
13299  Position = x;
13300  }
13301  if(PrefDirVector.at(x).XLinkPos == -1)
13302  {
13303  Error = true;
13304  ErrorString = "XLinkPos";
13305  Position = x;
13306  }
13307  if(PrefDirVector.at(x).SpeedTag == 0)
13308  {
13309  Error = true;
13310  ErrorString = "Tag";
13311  Position = x;
13312  }
13313  if(PrefDirVector.at(x).TrackVectorPosition == -1)
13314  {
13315  Error = true;
13316  ErrorString = "TrackVectorPosition";
13317  Position = x;
13318  }
13319  if(PrefDirVector.at(x).EXNumber == -1)
13320  {
13321  Error = true;
13322  ErrorString = "EXNumber";
13323  Position = x;
13324  }
13325  if(PrefDirVector.at(x).CheckCount != 9)
13326  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
13327  {
13328  Error = true;
13329  ErrorString = "CheckCount";
13330  Position = x;
13331  }
13332 // extra checks
13333  if(PrefDirVector.at(x).EXGraphicPtr == 0)
13334  {
13335  Error = true;
13336  ErrorString = "EntryGraphicPtr";
13337  Position = x;
13338  }
13339  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
13340  {
13341  Error = true;
13342  ErrorString = "EntryDirectionGraphicPtr";
13343  Position = x;
13344  }
13345 // end of extra checks
13346  if(x > 0)
13347  {
13348  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
13349  {
13350  Error = true;
13351  ErrorString = "Last XLink not connected to this element";
13352  Position = x;
13353  }
13354  }
13355  }
13356  if(Error)
13357  {
13358  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
13359  }
13360  else
13361  {
13362  Utilities->CallLogPop(153);
13363  return(true);
13364  }
13365 }
13366 
13367 // ---------------------------------------------------------------------------
13368 
13369 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
13370 /*
13371  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
13372  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
13373  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
13374  or a leading point.
13375 */
13376 {
13377  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13378  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
13379  {
13380  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
13381  {
13382  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
13383  {
13384  ErasePrefDirElementAt(1, PrefDirVecPos);
13385  }
13386  if(PrefDirVector.size() == 0)
13387  {
13388  Utilities->CallLogPop(154);
13389  return(true);
13390  }
13391  if(PrefDirVector.size() == 1)
13392  {
13393  PrefDirVector.at(x - 1).ELinkPos = -1;
13394  PrefDirVector.at(x - 1).ELink = -1;
13395  PrefDirVector.at(x - 1).XLinkPos = -1;
13396  PrefDirVector.at(x - 1).XLink = -1;
13397  PrefDirVector.at(x - 1).EXNumber = -1;
13398  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13399  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13400  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
13401  Utilities->CallLogPop(155);
13402  return(true);
13403  }
13404  // here with truncate element not first element, so ELink & ELinkPos set
13405  // unset XLink & Pos if a leading point
13406  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
13407  {
13408  PrefDirVector.at(x - 1).XLinkPos = -1;
13409  PrefDirVector.at(x - 1).XLink = -1;
13410  PrefDirVector.at(x - 1).EXNumber = -1;
13411  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13412  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13413  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
13414  Utilities->CallLogPop(156);
13415  return(true);
13416  }
13417  Utilities->CallLogPop(157);
13418  return(true);
13419  }
13420  }
13421  Utilities->CallLogPop(158);
13422  return(false);
13423 }
13424 
13425 // ---------------------------------------------------------------------------
13426 
13427 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
13428 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
13429 /*
13430  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
13431  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
13432  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
13433  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
13434  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
13435  displayed.
13436 */
13437 {
13438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
13439  AnsiString((short)BuildingPrefDir));
13440  int HPos, VPos;
13441 
13442  if(PrefDirSize() == 0)
13443  {
13444  Utilities->CallLogPop(159);
13445  return;
13446  }
13447  for(unsigned int x = 0; x < PrefDirSize(); x++)
13448  {
13449  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13450 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
13451 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
13452 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
13453  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
13454  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
13455  // only the front half of which will be overplotted by the back of the train, then when the train is
13456  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
13457  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13458  {
13459  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
13460  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
13461  {
13462  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13463  }
13464  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
13465  // Route, no direction if a single element
13466  {
13467  if(x == 0)
13468  {
13469  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13470  }
13471  if(x == (PrefDirSize() - 1))
13472  {
13473  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13474  }
13475  }
13476  }
13477  }
13478 
13479 // set start & end element colours if building a PrefDir
13480  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
13481  {
13482  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
13483  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
13484  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
13485  // set last element colour
13486  if(PrefDirSize() > 1)
13487  {
13488  unsigned int LatestPos = PrefDirSize() - 1;
13489  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
13490  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
13491  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
13492  }
13493  }
13494  Disp->Update();
13495  Utilities->CallLogPop(160);
13496 }
13497 
13498 // ---------------------------------------------------------------------------
13499 
13501 /*
13502  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
13503  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
13504 */
13505 {
13506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
13507  if(PrefDirSize() == 0)
13508  {
13509  Utilities->CallLogPop(1547);
13510  return;
13511  }
13512  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13513  bool FoundFlag;
13515  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13516 
13517  while(MMIT != PrefDir4MultiMap.end())
13518  {
13519  H = MMIT->first.first;
13520  V = MMIT->first.second;
13521  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13522  // always found in order, any missing have PrefDirPosx == -1
13523  if(PrefDirPos0 > -1)
13524  {
13525  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13526  }
13527  if(PrefDirPos1 > -1)
13528  {
13529  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
13530  }
13531  if(PrefDirPos2 > -1)
13532  {
13533  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
13534  }
13535  if(PrefDirPos3 > -1)
13536  {
13537  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
13538  }
13539  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13540  {
13541  // need to plot all 4 in order to obtain all the direction graphics
13542  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13543  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13544  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13545  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13546  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13547  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13548  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13549  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13550  MMIT++;
13551  MMIT++;
13552  MMIT++;
13553  MMIT++;
13554  }
13555  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13556  {
13557  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13558  {
13559  // 0 & 1 constitute the bidirectional PrefDir
13560  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13561  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13562  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13563  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13564  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13565  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13566  MMIT++;
13567  MMIT++;
13568  MMIT++;
13569  }
13570  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13571  {
13572  // 0 & 2 constitute the bidirectional PrefDir
13573  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13574  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13575  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13576  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13577  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13578  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13579  MMIT++;
13580  MMIT++;
13581  MMIT++;
13582  }
13583  else
13584  {
13585  // 1 & 2 constitute the bidirectional PrefDir
13586  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13587  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13588  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13589  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13590  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13591  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13592  MMIT++;
13593  MMIT++;
13594  MMIT++;
13595  }
13596  }
13597  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13598  {
13599  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13600  {
13601  // 0 & 1 constitute the bidirectional PrefDir
13602  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13603  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13604  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13605  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13606  MMIT++;
13607  MMIT++;
13608  }
13609  else
13610  {
13611  // 2 unidirectional PrefDirs
13612  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13613  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13614  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13615  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13616  MMIT++;
13617  MMIT++;
13618  }
13619  }
13620  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13621  {
13622  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13623  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13624  MMIT++;
13625  }
13626  }
13627  Disp->Update();
13628  Utilities->CallLogPop(1548);
13629 }
13630 
13631 // ---------------------------------------------------------------------------
13632 
13633 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
13634 {
13635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
13636  int TempInt;
13637 
13638  ClearPrefDir();
13639  int NumberOfPrefDirElements = 0;
13640 
13641  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13642  for(int x = 0; x < NumberOfPrefDirElements; x++)
13643  {
13644  VecFile >> TempInt; // TrackVectorPosition
13645  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
13646  LoadPrefDirElement.TrackVectorPosition = TempInt;
13647  VecFile >> TempInt;
13648  LoadPrefDirElement.ELink = TempInt;
13649  VecFile >> TempInt;
13650  LoadPrefDirElement.ELinkPos = TempInt;
13651  VecFile >> TempInt;
13652  LoadPrefDirElement.XLink = TempInt;
13653  VecFile >> TempInt;
13654  LoadPrefDirElement.XLinkPos = TempInt;
13655  VecFile >> TempInt;
13656  LoadPrefDirElement.EXNumber = TempInt;
13657  VecFile >> TempInt;
13658  LoadPrefDirElement.CheckCount = TempInt;
13659  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13660  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13661  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13662  if(!(LoadPrefDirElement.IsARoute))
13663  {
13664  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13665  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13666  }
13667  else
13668  {
13669  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13670  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13671  LoadPrefDirElement.PrefDirRoute);
13672  }
13673  StorePrefDirElement(5, LoadPrefDirElement);
13674  Utilities->LoadFileString(VecFile); // marker
13675  }
13677  Utilities->CallLogPop(161);
13678 }
13679 
13680 // ---------------------------------------------------------------------------
13681 
13682 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
13683 {
13684  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
13685  int TempInt;
13686 
13687  ClearPrefDir();
13688  int NumberOfPrefDirElements = 0;
13689 
13690  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13691  for(int x = 0; x < NumberOfPrefDirElements; x++)
13692  {
13693  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
13694  VecFile >> TempInt; // TrackVectorPosition
13695  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
13696  LoadPrefDirElement.TrackVectorPosition = TempInt;
13697  VecFile >> TempInt;
13698  LoadPrefDirElement.ELink = TempInt;
13699  VecFile >> TempInt;
13700  LoadPrefDirElement.ELinkPos = TempInt;
13701  VecFile >> TempInt;
13702  LoadPrefDirElement.XLink = TempInt;
13703  VecFile >> TempInt;
13704  LoadPrefDirElement.XLinkPos = TempInt;
13705  VecFile >> TempInt;
13706  LoadPrefDirElement.EXNumber = TempInt;
13707  VecFile >> TempInt;
13708  LoadPrefDirElement.CheckCount = TempInt;
13709  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13710  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13711  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13712  if(!(LoadPrefDirElement.IsARoute))
13713  {
13714  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13715  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13716  }
13717  else
13718  {
13719  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13720  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13721  LoadPrefDirElement.PrefDirRoute);
13722  }
13723  StorePrefDirElement(0, LoadPrefDirElement);
13724  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
13725  }
13727  Utilities->CallLogPop(1509);
13728 }
13729 
13730 // ---------------------------------------------------------------------------
13731 
13732 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
13733 /*
13734  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
13735  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
13736 */
13737 {
13738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
13739  int TempInt;
13740  int NumberOfPrefDirElements = 0;
13741 
13742  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13743  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
13744  {
13745  Utilities->CallLogPop(1152);
13746  return(false);
13747  }
13748  for(int x = 0; x < NumberOfPrefDirElements; x++)
13749  {
13750  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
13751  {
13752  Utilities->CallLogPop(1766);
13753  return(false);
13754  }
13755  VecFile >> TempInt;
13756  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
13757  {
13758  Utilities->CallLogPop(163);
13759  return(false);
13760  }
13761  VecFile >> TempInt;
13762  if((TempInt < -1) || (TempInt > 9)) // ELink
13763  {
13764  Utilities->CallLogPop(162);
13765  return(false);
13766  }
13767  VecFile >> TempInt;
13768  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
13769  {
13770  Utilities->CallLogPop(164);
13771  return(false);
13772  }
13773  VecFile >> TempInt;
13774  if((TempInt < -1) || (TempInt > 9)) // XLink
13775  {
13776  Utilities->CallLogPop(165);
13777  return(false);
13778  }
13779  VecFile >> TempInt;
13780  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
13781  {
13782  Utilities->CallLogPop(166);
13783  return(false);
13784  }
13785  VecFile >> TempInt;
13786  if((TempInt < -1) || (TempInt > 27)) // EXNumber
13787  {
13788  Utilities->CallLogPop(167);
13789  return(false);
13790  }
13791  VecFile >> TempInt;
13792  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
13793  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
13794  // ELinkPos, XLink, XLinkPos & EXNumber
13795  {
13796  Utilities->CallLogPop(168);
13797  return(false);
13798  }
13799  VecFile >> TempInt;
13800  if((TempInt != 0) && (TempInt != 1)) // RouteElement
13801  {
13802  Utilities->CallLogPop(1147);
13803  return(false);
13804  }
13805  VecFile >> TempInt;
13806  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
13807  {
13808  Utilities->CallLogPop(1510);
13809  return(false);
13810  }
13811  VecFile >> TempInt;
13812  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
13813  {
13814  Utilities->CallLogPop(1148);
13815  return(false);
13816  }
13817  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
13818  {
13819  Utilities->CallLogPop(1700);
13820  return(false);
13821  }
13822  }
13823  Utilities->CallLogPop(169);
13824  return(true);
13825 }
13826 
13827 // ---------------------------------------------------------------------------
13828 
13829 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
13830 {
13831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13832  int NumberOfPrefDirElements = PrefDirVector.size();
13833 
13834  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13835  for(int y = 0; y < NumberOfPrefDirElements; y++)
13836  {
13837  VecFile << y << '\n'; // extra
13838  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13839  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13840  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13841  VecFile << PrefDirVector.at(y).XLink << '\n';
13842  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13843  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13844  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13845  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13846  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13847  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13848  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13849  {
13850  VecFile << "************" << '\0' << '\n'; // marker
13851  }
13852  else
13853  {
13854  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13855  }
13856  }
13857  Utilities->CallLogPop(170);
13858 }
13859 
13860 // ---------------------------------------------------------------------------
13861 
13862 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13863 {
13864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13865  int NumberOfSearchElements = SearchVector.size();
13866 
13867  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13868  for(int y = 0; y < NumberOfSearchElements; y++)
13869  {
13870  VecFile << y << '\n'; // extra
13871  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13872  VecFile << SearchVector.at(y).ELink << '\n';
13873  VecFile << SearchVector.at(y).ELinkPos << '\n';
13874  VecFile << SearchVector.at(y).XLink << '\n';
13875  VecFile << SearchVector.at(y).XLinkPos << '\n';
13876  VecFile << SearchVector.at(y).EXNumber << '\n';
13877  VecFile << SearchVector.at(y).CheckCount << '\n';
13878  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13879  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13880  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13881  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13882  {
13883  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13884  }
13885  else
13886  {
13887  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13888  }
13889  }
13890  Utilities->CallLogPop(1847);
13891 }
13892 
13893 // ---------------------------------------------------------------------------
13894 
13895 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13896 /*
13897  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13898  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13899 */
13900 {
13901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13902  AnsiString(VLoc));
13903  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13904 
13905  if(VecPos > -1)
13906  {
13907  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13908  }
13909  else
13910  {
13911  Utilities->CallLogPop(171);
13912  return;
13913  }
13914  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13915  if(VecPos > -1)
13916  {
13917  ErasePrefDirElementAt(3, VecPos);
13918  }
13919  else
13920  {
13921  Utilities->CallLogPop(172);
13922  return;
13923  }
13924  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13925  if(VecPos > -1)
13926  {
13927  ErasePrefDirElementAt(4, VecPos);
13928  }
13929  else
13930  {
13931  Utilities->CallLogPop(173);
13932  return;
13933  }
13934  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13935  if(VecPos > -1)
13936  {
13937  ErasePrefDirElementAt(5, VecPos);
13938  }
13939  else
13940  {
13941  Utilities->CallLogPop(174);
13942  return;
13943  }
13944  Utilities->CallLogPop(175);
13945 }
13946 
13947 // ---------------------------------------------------------------------------
13948 /*
13949  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13950  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13951 
13952  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13953  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13954  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13955  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13956  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13957  PrefDirVector to correspond to the new track layout.
13958 
13959  {
13960  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13961  if(PrefDirSize() == 0)
13962  {
13963  Utilities->CallLogPop(176);
13964  return;
13965  }
13966  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13967  {
13968  int TV = PrefDirVector.at(x).TrackVectorPosition;
13969  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13970  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13971  if(Track->BlankElementAt(0, TV))
13972  {
13973  ErasePrefDirElementAt(6, x);
13974  }
13975  //if was a blankelement at x then ConnELink and ConnXLink both -1
13976  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13977  {
13978  ErasePrefDirElementAt(7, x);
13979  }
13980  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13981  //needs to be erased once, but if don't use 'else' then will erase two elements
13982  //since 'x' will correspond to the element after the first erased element
13983  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13984  {
13985  ErasePrefDirElementAt(8, x);
13986  }
13987  }
13988  Utilities->CallLogPop(177);
13989  }
13990 */
13991 // ---------------------------------------------------------------------------
13992 
13993 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13994 /*
13995  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13996  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13997 */
13998 {
13999  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
14000  bool AlreadyPresent, FoundFlag;
14001  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14002 
14003  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
14004  {
14005  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
14006  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14007  AlreadyPresent = false;
14008  if(FoundFlag)
14009  {
14010  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
14011  {
14012  AlreadyPresent = true;
14013  }
14014  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
14015  {
14016  AlreadyPresent = true;
14017  }
14018  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
14019  {
14020  AlreadyPresent = true;
14021  }
14022  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
14023  {
14024  AlreadyPresent = true;
14025  }
14026  }
14027  if(!AlreadyPresent)
14028  {
14029  StorePrefDirElement(4, TempElement);
14030  }
14031  }
14033  Utilities->CallLogPop(178);
14034 }
14035 /* earlier brute force search
14036  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
14037  {
14038  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
14039  bool AlreadyPresent = false;
14040  for(unsigned int y = 0;y<PrefDirSize();y++)
14041  {
14042  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
14043  }
14044  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
14045  }
14046 */
14047 
14048 // ---------------------------------------------------------------------------
14049 
14051 /*
14052  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
14053  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
14054  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
14055  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
14056  positions are likely to have changed, so this function is called to reset all the necessary connections and
14057  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
14058  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
14059  shouldn't have changed.
14060 */
14061 {
14062  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
14063  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14064  {
14065  bool FoundFlag;
14066  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14067  if(FoundFlag)
14068  {
14069  PrefDirVector.at(x).TrackVectorPosition = VecPos;
14070  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
14071  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
14072  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
14073  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
14074  for(unsigned int z = 0; z < 4; z++)
14075  {
14076  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
14077  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
14078  }
14079  }
14080  else
14081  {
14082  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
14083  }
14084  }
14085  Utilities->CallLogPop(179);
14086 }
14087 
14088 // ---------------------------------------------------------------------------
14089 
14091 /*
14092  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
14093 */
14094 {
14095  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
14096  bool DiscrepancyFound = false;
14097 
14098  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14099  {
14100  bool FoundFlag;
14101  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14102  if(FoundFlag)
14103  {
14104  TPrefDirElement PE = PrefDirVector.at(x);
14105  if(PE.TrackVectorPosition != VecPos)
14106  {
14107  DiscrepancyFound = true;
14108  break;
14109  }
14110  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
14111  {
14112  DiscrepancyFound = true;
14113  break;
14114  }
14115  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
14116  {
14117  DiscrepancyFound = true;
14118  break;
14119  }
14120  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
14121  {
14122  DiscrepancyFound = true;
14123  break;
14124  }
14125  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
14126  {
14127  DiscrepancyFound = true;
14128  break;
14129  }
14130  }
14131  else
14132  {
14133  DiscrepancyFound = true;
14134  }
14135  }
14136  if(DiscrepancyFound)
14137  {
14138  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
14139  ClearPrefDir(); // also clears multimap
14140  }
14141  Utilities->CallLogPop(1436);
14142 }
14143 
14144 // ---------------------------------------------------------------------------
14145 
14147 /*
14148  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
14149  return true for OK
14150 */
14151 {
14152  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
14153  bool DiscrepancyFound = false;
14154 
14155  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14156  {
14157  bool FoundFlag;
14158  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14159  if(FoundFlag)
14160  {
14161  TPrefDirElement PE = PrefDirVector.at(x);
14162  if(PE.TrackVectorPosition != VecPos)
14163  {
14164  DiscrepancyFound = true;
14165  }
14166  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
14167  {
14168  DiscrepancyFound = true;
14169  break;
14170  }
14171  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
14172  {
14173  DiscrepancyFound = true;
14174  break;
14175  }
14176  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
14177  {
14178  DiscrepancyFound = true;
14179  break;
14180  }
14181  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
14182  {
14183  DiscrepancyFound = true;
14184  break;
14185  }
14186  }
14187  else
14188  {
14189  DiscrepancyFound = true;
14190  }
14191  }
14192  Utilities->CallLogPop(1512);
14193  return(!DiscrepancyFound);
14194 }
14195 
14196 // ---------------------------------------------------------------------------
14197 
14198 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
14199 /*
14200  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
14201  turn and for the overall sizes.
14202 */
14203 {
14204  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
14205  bool FoundFlag = false;
14206  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
14207 
14208  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
14209  {
14210  TPrefDirElement CheckElement = PrefDirVector.at(a);
14211  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
14212  if(!FoundFlag)
14213  {
14214  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
14215  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
14216  }
14217  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
14218  {
14219  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
14220  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
14221  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
14222  }
14223  }
14224  if(PrefDirVector.size() != PrefDir4MultiMap.size())
14225  {
14226  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
14227  + " Caller=" + (AnsiString)Caller);
14228  }
14229  Utilities->CallLogPop(180);
14230 }
14231 
14232 // ---------------------------------------------------------------------------
14233 
14234 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
14235  int &PrefDirPos3)
14236 /*
14237  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
14238  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
14239  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
14240  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
14241  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
14242 */
14243 {
14244  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
14245  AnsiString(VLoc));
14246  THVPair PrefDirMapKeyPair;
14247 
14248  PrefDirPos0 = -1;
14249  PrefDirPos1 = -1;
14250  PrefDirPos2 = -1;
14251  PrefDirPos3 = -1;
14252  FoundFlag = false;
14253  PrefDirMapKeyPair.first = HLoc;
14254  PrefDirMapKeyPair.second = VLoc;
14255  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14256 
14257  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
14258  if(ItPair.first == ItPair.second) //none found
14259  {
14260  Utilities->CallLogPop(181);
14261  return;
14262  }
14263  else
14264  {
14265  FoundFlag = true;
14266  PrefDirPos0 = ItPair.first->second;
14267  ItPair.first++;
14268  if(ItPair.first == ItPair.second)
14269  {
14270  Utilities->CallLogPop(182); //only one found
14271  return;
14272  }
14273  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14274  {
14275  PrefDirPos1 = ItPair.first->second;
14276  }
14277  ItPair.first++;
14278  if(ItPair.first == ItPair.second)
14279  {
14280  Utilities->CallLogPop(183); //2 found
14281  return;
14282  }
14283  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14284  {
14285  PrefDirPos2 = ItPair.first->second;
14286  }
14287  ItPair.first++;
14288  if(ItPair.first == ItPair.second)
14289  {
14290  Utilities->CallLogPop(184); //3 found
14291  return;
14292  }
14293  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14294  {
14295  PrefDirPos3 = ItPair.first->second; //4 found
14296  }
14297  }
14298  Utilities->CallLogPop(185);
14299 }
14300 
14301 // ---------------------------------------------------------------------------
14302 
14303 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14304 { //not used after modified the pref dir checking function at v2.13.0
14305  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
14306  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14307  try
14308  {
14309  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
14310  + "," + AnsiString(LinkNumberPos));
14311  bool FoundFlag;
14312  int PD0, PD1, PD2, PD3;
14313  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14314  {
14315  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14316  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14317  PD0, PD1, PD2, PD3);
14318  if(!FoundFlag)
14319  {
14320  Utilities->CallLogPop(2282);
14321  return(false);
14322  }
14323  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14324  {
14325  if(PD0 > -1)
14326  {
14327  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
14328  {
14329  LinkedPrefDirVectorNumber = PD0;
14330  Utilities->CallLogPop(2283);
14331  return(true);
14332  }
14333  }
14334  if(PD1 > -1)
14335  {
14336  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
14337  {
14338  LinkedPrefDirVectorNumber = PD1;
14339  Utilities->CallLogPop(2284);
14340  return(true);
14341  }
14342  }
14343  }
14344  if(PD0 > -1)
14345  {
14346  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
14347  {
14348  LinkedPrefDirVectorNumber = PD0;
14349  Utilities->CallLogPop(2285);
14350  return(true);
14351  }
14352  }
14353  if(PD1 > -1)
14354  {
14355  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
14356  {
14357  LinkedPrefDirVectorNumber = PD1;
14358  Utilities->CallLogPop(2286);
14359  return(true);
14360  }
14361  }
14362  if(PD2 > -1)
14363  {
14364  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
14365  {
14366  LinkedPrefDirVectorNumber = PD2;
14367  Utilities->CallLogPop(2287);
14368  return(true);
14369  }
14370  }
14371  if(PD3 > -1)
14372  {
14373  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
14374  {
14375  LinkedPrefDirVectorNumber = PD3;
14376  Utilities->CallLogPop(2288);
14377  return(true);
14378  }
14379  }
14380  LinkedPrefDirVectorNumber = -1;
14381  Utilities->CallLogPop(2289);
14382  return(false);
14383  }
14384  else //buffer or continuation, no link at position 0 but not a failure
14385  {
14386  LinkedPrefDirVectorNumber = -1;
14387  Utilities->CallLogPop(2290);
14388  return(true);
14389  }
14390  }
14391  catch(const Exception &e) //non error catch
14392  {
14393  LinkedPrefDirVectorNumber = -1;
14394  Utilities->CallLogPop(2291);
14395  return(false);
14396  }
14397 }
14398 
14399 // ---------------------------------------------------------------------------
14400 
14401 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14402 { //not used after modified the pref dir checking function at v2.13.0
14403  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
14404  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14405  try
14406  {
14407  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
14408  + "," + AnsiString(LinkNumberPos));
14409  bool FoundFlag;
14410  int PD0, PD1, PD2, PD3;
14411  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14412  {
14413  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14414  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14415  PD0, PD1, PD2, PD3);
14416  if(!FoundFlag)
14417  {
14418  Utilities->CallLogPop(2468);
14419  return(false);
14420  }
14421  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14422  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
14423  if(PD0 > -1)
14424  {
14425  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
14426  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
14427  {
14428  LinkedPrefDirVectorNumber = PD0;
14429  Utilities->CallLogPop(2469);
14430  return(true);
14431  }
14432  }
14433  if(PD1 > -1)
14434  {
14435  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
14436  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
14437  {
14438  LinkedPrefDirVectorNumber = PD1;
14439  Utilities->CallLogPop(2470);
14440  return(true);
14441  }
14442  }
14443  LinkedPrefDirVectorNumber = -1;
14444  Utilities->CallLogPop(2471);
14445  return(false);
14446  }
14447  if(PD0 > -1)
14448  {
14449  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14450  {
14451  LinkedPrefDirVectorNumber = PD0;
14452  Utilities->CallLogPop(2472);
14453  return(true);
14454  }
14455  }
14456  if(PD1 > -1)
14457  {
14458  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14459  {
14460  LinkedPrefDirVectorNumber = PD1;
14461  Utilities->CallLogPop(2473);
14462  return(true);
14463  }
14464  }
14465  if(PD2 > -1)
14466  {
14467  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14468  {
14469  LinkedPrefDirVectorNumber = PD2;
14470  Utilities->CallLogPop(2474);
14471  return(true);
14472  }
14473  }
14474  if(PD3 > -1)
14475  {
14476  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14477  {
14478  LinkedPrefDirVectorNumber = PD3;
14479  Utilities->CallLogPop(2475);
14480  return(true);
14481  }
14482  }
14483  LinkedPrefDirVectorNumber = -1;
14484  Utilities->CallLogPop(2476);
14485  return(false);
14486  }
14487  else //buffer or continuation, no link at position 0 but not a failure
14488  {
14489  LinkedPrefDirVectorNumber = -1;
14490  Utilities->CallLogPop(2477);
14491  return(true);
14492  }
14493  }
14494  catch(const Exception &e) //non error catch
14495  {
14496  LinkedPrefDirVectorNumber = -1;
14497  Utilities->CallLogPop(2478);
14498  return(false);
14499  }
14500 }
14501 
14502 // ---------------------------------------------------------------------------
14503 
14505 {
14506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
14507  bool FoundFlag; //not used
14508  int PD0, PD1, PD2, PD3;
14509  //recover all PDs at the H & V of PDPtr
14510  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
14511 
14512  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
14513  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
14514 
14515  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
14516  {
14517  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
14518  {
14519  Utilities->CallLogPop(2292);
14520  return(true);
14521  }
14522  }
14523  if(PD1 > -1)
14524  {
14525  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
14526  {
14527  Utilities->CallLogPop(2293);
14528  return(true);
14529  }
14530  }
14531  if(PD2 > -1)
14532  {
14533  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
14534  {
14535  Utilities->CallLogPop(2294);
14536  return(true);
14537  }
14538  }
14539  if(PD3 > -1)
14540  {
14541  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
14542  {
14543  Utilities->CallLogPop(2295);
14544  return(true);
14545  }
14546  }
14547  Utilities->CallLogPop(2296);
14548  return(false);
14549 }
14550 
14551 // ---------------------------------------------------------------------------
14552 
14553 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
14554 /*
14555  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
14556 */
14557 {
14558  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
14559  PrefDirVector.push_back(LoadPrefDirElement);
14560  THVPair PrefDir4MultiMapKeyPair;
14561  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
14562 
14563  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
14564  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
14565  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
14566  PrefDir4MultiMapEntry.second = LastElementNumber(68);
14567  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
14568 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
14569  Utilities->CallLogPop(186);
14570 }
14571 
14572 // ---------------------------------------------------------------------------
14573 
14574 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
14575 /*
14576  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
14577  4MultiMap if they are greater than the erased value.
14578 */
14579 {
14580  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
14581  bool FoundFlag;
14582 
14583  if(!PrefDirVector.empty())
14584  {
14585  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
14586  if(!FoundFlag)
14587  {
14588  throw Exception("Failed to find PrefDir4MultiMap erase element");
14589  }
14590  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
14591  PrefDir4MultiMap.erase(EraseIt);
14592  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
14594  }
14595  Utilities->CallLogPop(187);
14596 }
14597 
14598 // ---------------------------------------------------------------------------
14599 
14600 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
14601 /*
14602  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
14603  4MultiMap if they are greater than the erased value.
14604 */
14605 {
14606  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
14607  AnsiString(ErasedElementNumber));
14608  if(!PrefDir4MultiMap.empty())
14609  {
14610  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
14611  {
14612  if(MapPtr->second > ErasedElementNumber)
14613  {
14614  MapPtr->second--;
14615  }
14616  }
14617  }
14618  Utilities->CallLogPop(1450);
14619 }
14620 
14621 // ---------------------------------------------------------------------------
14622 
14623 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
14624 /*
14625  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
14626  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
14627  nothing is found this is an error but the error message is given in the calling function.
14628 */
14629 {
14630  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
14631  FoundFlag = false;
14632  if(PrefDirVectorPosition >= PrefDirVector.size())
14633  {
14634  throw Exception("PrefDirVectorPosition out of range");
14635  }
14636  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
14637  THVPair PrefDir4MultiMapKeyPair;
14638 
14639  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
14640  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
14641  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14642 
14643  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14644  if(ItPair.first == ItPair.second)
14645  {
14646  Utilities->CallLogPop(188);
14647  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
14648  }
14649  else
14650  {
14651  if(ItPair.first->second == PrefDirVectorPosition)
14652  {
14653  FoundFlag = true;
14654  Utilities->CallLogPop(189);
14655  return(ItPair.first);
14656  }
14657  ItPair.first++;
14658  if(ItPair.first == ItPair.second)
14659  {
14660  Utilities->CallLogPop(190);
14661  return(ItPair.first); // nothing found
14662  }
14663  if(ItPair.first->second == PrefDirVectorPosition)
14664  {
14665  FoundFlag = true;
14666  Utilities->CallLogPop(191);
14667  return(ItPair.first);
14668  }
14669  ItPair.first++;
14670  if(ItPair.first == ItPair.second)
14671  {
14672  Utilities->CallLogPop(192);
14673  return(ItPair.first); // nothing found
14674  }
14675  if(ItPair.first->second == PrefDirVectorPosition)
14676  {
14677  FoundFlag = true;
14678  Utilities->CallLogPop(193);
14679  return(ItPair.first);
14680  }
14681  ItPair.first++;
14682  if(ItPair.first == ItPair.second)
14683  {
14684  Utilities->CallLogPop(194);
14685  return(ItPair.first); // nothing found
14686  }
14687  if(ItPair.first->second == PrefDirVectorPosition)
14688  {
14689  FoundFlag = true;
14690  Utilities->CallLogPop(195);
14691  return(ItPair.first);
14692  }
14693  }
14694  Utilities->CallLogPop(196);
14695  return(ItPair.first); // nothing found
14696 }
14697 
14698 // ---------------------------------------------------------------------------
14699 
14700 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
14701 /*
14702  Although there may be up to four entries at one H & V position this function gets just one. It is
14703  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
14704  at H & V.
14705 */
14706 {
14707  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
14708  THVPair PrefDir4MultiMapKeyPair;
14709 
14710  PrefDir4MultiMapKeyPair.first = HLoc;
14711  PrefDir4MultiMapKeyPair.second = VLoc;
14712  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14713 
14714  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14715  if(ItPair.first == ItPair.second) // nothing found
14716  {
14717  Utilities->CallLogPop(197);
14718  return(-1);
14719  }
14720  else
14721  {
14722  Utilities->CallLogPop(198);
14723  return(ItPair.first->second);
14724  }
14725 }
14726 
14727 // ---------------------------------------------------------------------------
14728 
14729 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
14730 {
14731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
14732  bool ErasedFlag = false;
14733 
14734  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
14735  {
14736  if(PrefDirSize() == 0)
14737  {
14738  Utilities->CallLogPop(1511);
14739  return;
14740  }
14741  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
14742  {
14743  ErasedFlag = false;
14744  // use 'else' to ensure don't try to access an erased element
14745  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
14746  {
14747  ErasePrefDirElementAt(11, x);
14748  ErasedFlag = true;
14749  }
14750  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
14751  {
14752  ErasePrefDirElementAt(12, x);
14753  ErasedFlag = true;
14754  }
14755  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
14756  {
14757  ErasePrefDirElementAt(13, x);
14758  ErasedFlag = true;
14759  }
14760  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
14761  {
14762  ErasePrefDirElementAt(9, x);
14763  ErasedFlag = true;
14764  }
14765  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
14766  {
14767  ErasePrefDirElementAt(10, x);
14768  ErasedFlag = true;
14769  }
14770  if(!ErasedFlag)
14771  {
14772  // don't use 'else' here as may be more than one that need decrementing
14773  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
14774  {
14775  PrefDirVector.at(x).TrackVectorPosition--;
14776  }
14777  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
14778  {
14779  PrefDirVector.at(x).Conn[0]--;
14780  }
14781  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
14782  {
14783  PrefDirVector.at(x).Conn[1]--;
14784  }
14785  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
14786  {
14787  PrefDirVector.at(x).Conn[2]--;
14788  }
14789  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
14790  {
14791  PrefDirVector.at(x).Conn[3]--;
14792  }
14793  }
14794  }
14795  }
14796  Utilities->CallLogPop(1434);
14797 }
14798 
14799 // ---------------------------------------------------------------------------
14800 
14801 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
14802 {
14803  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
14804  OverallDistance = 0;
14805  OverallSpeedLimit = 0;
14806  LeadingPointsAtLastElement = false;
14807  if(PrefDirSize() == 0) // shouldn't be empty when this called
14808  {
14809  Utilities->CallLogPop(1491);
14810  return;
14811  }
14812  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
14813  {
14814  LeadingPointsAtLastElement = true;
14815  Utilities->CallLogPop(1492);
14816  return;
14817  }
14818  for(unsigned int x = 0; x < PrefDirSize(); x++)
14819  {
14820  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
14821  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
14822  {
14823  OverallDistance += PrefDirElement.Length23;
14824  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14825  {
14826  if(x == 0)
14827  {
14828  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
14829  }
14830  else
14831  {
14832  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14833  {
14834  OverallSpeedLimit = -1;
14835  }
14836  }
14837  }
14838  }
14839  else
14840  {
14841  OverallDistance += PrefDirElement.Length01;
14842  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14843  {
14844  if(x == 0)
14845  {
14846  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14847  }
14848  else
14849  {
14850  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14851  {
14852  OverallSpeedLimit = -1;
14853  }
14854  }
14855  }
14856  }
14857  }
14858  Utilities->CallLogPop(1529);
14859 }
14860 
14861 // ---------------------------------------------------------------------------
14862 
14863 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14864 {
14865  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14866  if(PrefDirSize() == 0)
14867  {
14868  Utilities->CallLogPop(1564);
14869  return;
14870  }
14871  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14872  bool FoundFlag;
14874  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14875 
14876  while(MMIT != PrefDir4MultiMap.end())
14877  {
14878  HLoc = MMIT->first.first;
14879  VLoc = MMIT->first.second;
14880  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14881  H = HLoc - Track->GetHLocMin();
14882  V = VLoc - Track->GetVLocMin();
14883  // always found in order, any missing have PrefDirPosx == -1
14884  if(PrefDirPos0 > -1)
14885  {
14886  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14887  }
14888  if(PrefDirPos1 > -1)
14889  {
14890  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14891  }
14892  if(PrefDirPos2 > -1)
14893  {
14894  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14895  }
14896  if(PrefDirPos3 > -1)
14897  {
14898  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14899  }
14900  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14901  {
14902  // need to plot all 4 in order to obtain all the direction graphics
14903  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14904  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14905  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14906  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14907  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14908  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14909  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14910  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14911  MMIT++;
14912  MMIT++;
14913  MMIT++;
14914  MMIT++;
14915  }
14916  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14917  {
14918  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14919  {
14920  // 0 & 1 constitute the bidirectional PrefDir
14921  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14922  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14923  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14924  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14925  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14926  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14927  MMIT++;
14928  MMIT++;
14929  MMIT++;
14930  }
14931  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14932  {
14933  // 0 & 2 constitute the bidirectional PrefDir
14934  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14935  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14936  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14937  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14938  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14939  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14940  MMIT++;
14941  MMIT++;
14942  MMIT++;
14943  }
14944  else
14945  {
14946  // 1 & 2 constitute the bidirectional PrefDir
14947  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14948  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14949  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14950  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14951  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14952  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14953  MMIT++;
14954  MMIT++;
14955  MMIT++;
14956  }
14957  }
14958  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14959  {
14960  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14961  {
14962  // 0 & 1 constitute the bidirectional PrefDir
14963  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14964  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14965  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14966  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14967  MMIT++;
14968  MMIT++;
14969  }
14970  else
14971  {
14972  // 2 unidirectional PrefDirs
14973  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14974  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14975  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14976  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14977  MMIT++;
14978  MMIT++;
14979  }
14980  }
14981  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14982  {
14983  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14984  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14985  MMIT++;
14986  }
14987  }
14988  Utilities->CallLogPop(1565);
14989 }
14990 
14991 // ---------------------------------------------------------------------------
14992 
14993 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14994 /*
14995  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14996  level crossing, signals with wrong direction set, or buffers.
14997 */
14998 {
14999  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
15000  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
15001  bool FoundFlag;
15003  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
15004 
15005  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
15006  ElementIn.VLoc)))
15007  {
15008  Utilities->CallLogPop(1982);
15009  return(false);
15010  }
15011  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
15012  {
15013  Utilities->CallLogPop(1983);
15014  return(false);
15015  }
15016 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
15017  {
15018  Utilities->CallLogPop(1995);
15019  return(false);
15020  }
15021 */
15022 // Now check that there is only a single prefdir set
15023  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15024 // always found in order, any missing have PrefDirPosx == -1
15025  if(PrefDirPos0 > -1)
15026  {
15027  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
15028  }
15029  if(PrefDirPos1 > -1)
15030  {
15031  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
15032  }
15033  if(PrefDirPos2 > -1)
15034  {
15035  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
15036  }
15037  if(PrefDirPos3 > -1)
15038  {
15039  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
15040  }
15041  if(PrefDirPos3 > -1) // 4 found, all bidirectional
15042  {
15043  Utilities->CallLogPop(1984);
15044  return(false);
15045  }
15046  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
15047  {
15048  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
15049  {
15050  Utilities->CallLogPop(1985);
15051  return(false);
15052  }
15053  else
15054  {
15055  Utilities->CallLogPop(1986);
15056  return(true);
15057  }
15058  }
15059  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
15060  {
15061  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
15062  {
15063  Utilities->CallLogPop(1987);
15064  return(false);
15065  }
15066  else
15067  {
15068  Utilities->CallLogPop(1988);
15069  return(true);
15070  }
15071  }
15072  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
15073  {
15074  if(PrefDirElement0.XLinkPos == EntryPos)
15075  {
15076  Utilities->CallLogPop(1989);
15077  return(false);
15078  }
15079  else
15080  {
15081  Utilities->CallLogPop(1990);
15082  return(true);
15083  }
15084  }
15085  else
15086  {
15087  Utilities->CallLogPop(1991);
15088  return(false); // none found
15089  }
15090 }
15091 
15092 // ---------------------------------------------------------------------------
15093 
15095 {
15096 /* //Added at v2.1.0
15097  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
15098  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
15099  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
15100  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
15101  and can be modelled better anyway.
15102 
15103  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
15104  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
15105  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
15106  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
15107  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
15108  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
15109 */
15110  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
15111  ElementIn.VLoc + "," + XLink);
15112  int TrackVecPos;
15113  bool TrackFoundFlag;
15114  TTrackElement TempTrackElement;
15115 
15116  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
15117  {
15118  Utilities->CallLogPop(2047);
15119  return(false);
15120  }
15121 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
15122  if(XLink == 1)
15123  {
15124  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
15125  if(TrackFoundFlag)
15126  {
15127  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
15128  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
15129  {
15130  Utilities->CallLogPop(2048);
15131  return(true);
15132  }
15133  }
15134  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
15135  if(TrackFoundFlag)
15136  {
15137  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
15138  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
15139  {
15140  Utilities->CallLogPop(2049);
15141  return(true);
15142  }
15143  }
15144  }
15145 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
15146  if(XLink == 3)
15147  {
15148  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
15149  if(TrackFoundFlag)
15150  {
15151  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
15152  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
15153  {
15154  Utilities->CallLogPop(2050);
15155  return(true);
15156  }
15157  }
15158  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
15159  if(TrackFoundFlag)
15160  {
15161  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
15162  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
15163  {
15164  Utilities->CallLogPop(2051);
15165  return(true);
15166  }
15167  }
15168  }
15169 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
15170  if(XLink == 7)
15171  {
15172  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
15173  if(TrackFoundFlag)
15174  {
15175  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
15176  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
15177  {
15178  Utilities->CallLogPop(2052);
15179  return(true);
15180  }
15181  }
15182  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
15183  if(TrackFoundFlag)
15184  {
15185  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
15186  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
15187  {
15188  Utilities->CallLogPop(2053);
15189  return(true);
15190  }
15191  }
15192  }
15193 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
15194  if(XLink == 9)
15195  {
15196  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
15197  if(TrackFoundFlag)
15198  {
15199  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
15200  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
15201  {
15202  Utilities->CallLogPop(2054);
15203  return(true);
15204  }
15205  }
15206  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
15207  if(TrackFoundFlag)
15208  {
15209  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
15210  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
15211  {
15212  Utilities->CallLogPop(2055);
15213  return(true);
15214  }
15215  }
15216  }
15217  Utilities->CallLogPop(2056);
15218  return(false);
15219 }
15220 
15221 // ---------------------------------------------------------------------------
15222 
15223 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
15224 {
15225 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
15226  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
15227  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
15228  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
15229  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
15230 */
15231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
15233  bool FoundFlag, ContFlag, FoundElements = false;
15234  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
15235  TPrefDirElement NextElement;
15236 
15237  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
15238  {
15239  LastIteratorValue++;
15240  ContFlag = false;
15241  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
15242  {
15243  continue;
15244  }
15245 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
15246  {
15247  continue;
15248  }
15249 */
15250 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
15251  // found a potential route start point
15252  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
15253  {
15254  continue;
15255  }
15256  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
15257  {
15258  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
15259  if(PDVIt->TrackType == Continuation)
15260  {
15261  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
15262  {
15263  continue;
15264  }
15265  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
15266  {
15267  continue;
15268  }
15269  }
15270  StartElement = *PDVIt;
15271 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
15272  // diverging track on which there was no pref dir. See below for 2 required changes.
15273  }
15274  else
15275  {
15276  continue;
15277  }
15278  // now track along until find a signal or continuation, checking validity for each element
15279  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
15280  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
15281  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15282  if(PrefDirPos0 == -1) // no continuing prefdir
15283  {
15284  continue;
15285  }
15286  bool NextElementFoundFlag = false;
15287  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15288  {
15289  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
15290  NextElementFoundFlag = true;
15291  }
15292  if(PrefDirPos1 > -1)
15293  {
15294  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15295  {
15296  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
15297  NextElementFoundFlag = true;
15298  }
15299  }
15300  if(PrefDirPos2 > -1)
15301  {
15302  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15303  {
15304  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
15305  NextElementFoundFlag = true;
15306  }
15307  }
15308  if(PrefDirPos3 > -1)
15309  {
15310  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15311  {
15312  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
15313  NextElementFoundFlag = true;
15314  }
15315  }
15316  if(!NextElementFoundFlag)
15317  {
15318  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15319 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
15320  }
15321  while(true)
15322  {
15323  // check validity
15324  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
15325  {
15326  ContFlag = true;
15327  break;
15328  }
15329  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
15330  {
15331  ContFlag = true;
15332  break;
15333  }
15334  // check if in a route, providing not a signal, as a signal might be at the start of a route
15335  if(NextElement.TrackType != SignalPost)
15336  {
15337  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
15338  {
15339  ContFlag = true;
15340  break;
15341  }
15342  }
15343  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
15344  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
15345  {
15346  EndElement = NextElement;
15347  break;
15348  }
15349  // get the next element in the sequence
15350  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
15351  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
15352  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15353  if(PrefDirPos0 == -1) // no continuing prefdir
15354  {
15355  ContFlag = true;
15356  break;
15357  }
15358  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15359  {
15360  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
15361  continue;
15362  }
15363  if(PrefDirPos1 > -1)
15364  {
15365  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15366  {
15367  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
15368  continue;
15369  }
15370  }
15371  if(PrefDirPos2 > -1)
15372  {
15373  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15374  {
15375  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
15376  continue;
15377  }
15378  }
15379  if(PrefDirPos3 > -1)
15380  {
15381  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15382  {
15383  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
15384  continue;
15385  }
15386  }
15387  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
15388  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
15389  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
15390  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
15391  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
15392  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
15393  {
15394  ContFlag = true;
15395  break;
15396  }
15397  else
15398  {
15399  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15400  // could drop the bridge test but keep it to show the change history
15401  break;
15402 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
15403  }
15404  }
15405  if(ContFlag)
15406  {
15407  continue;
15408  }
15409  // else have start and end elements set & all elements valid, so set up the route segment
15410  FoundElements = true;
15411  break;
15412  }
15413  if(FoundElements)
15414  {
15415  Utilities->CallLogPop(1992);
15416  return(true);
15417  }
15418  else
15419  {
15420  Utilities->CallLogPop(1993);
15421  return(false);
15422  }
15423 }
15424 
15425 // ---------------------------------------------------------------------------
15426 // TOneRoute
15427 // ---------------------------------------------------------------------------
15428 
15429 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
15430 {
15431 /* General:
15432  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
15433  containing all the new elements to form the route. When complete, the SearchVector is converted into route
15434  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
15435  route will use automatic signals or not.
15436  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
15437  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
15438  elements, so additional work is needed to complete all their members before they are ready for conversion into
15439  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
15440  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
15441  ConvertAndAdd.......
15442 */
15443  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15444  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
15445  ClearRoute();
15446  int TrackVectorPosition;
15447  TTrackElement TrackElement;
15448  TPrefDirElement FirstElement, LastElement;
15449 
15450  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15451  {
15452  Utilities->CallLogPop(199);
15453  return(false);
15454  }
15455  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
15456  {
15457  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
15458  Utilities->CallLogPop(1996);
15459  return(false);
15460  }
15461  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15462  {
15463  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation to start or add to a route, or points to change them");
15464  Utilities->CallLogPop(200);
15465  return(false);
15466  }
15467  if(Track->IsLCAtHV(18, HLoc, VLoc))
15468  {
15469  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
15470  Utilities->CallLogPop(1909);
15471  return(false);
15472  }
15473 // check if selected a train & disallow if so
15474  if(TrackElement.TrainIDOnElement > -1)
15475  {
15476  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
15477  Utilities->CallLogPop(202);
15478  return(false);
15479  }
15480 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15481  TPrefDirElement PrefDirElement;
15482  int LockedVectorNumber;
15483 
15484  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15485  {
15486  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
15487  Utilities->CallLogPop(203);
15488  return(false);
15489  }
15490  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15491  {
15492  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
15493  Utilities->CallLogPop(204);
15494  return(false);
15495  }
15497  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
15498 // signal in an autosig route & follow with a non-autosig route
15499 
15500  TPrefDirElement BlankElement;
15501 
15502  StartElement1 = BlankElement;
15503  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
15504 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
15505  bool InPrefDirFlag = false;
15506 
15507  bool FoundFlag;
15508  int PrefDirPos0 = -1;
15509  int PrefDirPos1 = -1;
15510  int PrefDirPos2 = -1;
15511  int PrefDirPos3 = -1;
15512 
15514  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15515  int PrefDirVecPos[4] =
15516  {
15517  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15518  };
15519 
15520  for(int x = 0; x < 4; x++)
15521  {
15522  int b = PrefDirVecPos[x];
15523  if(b > -1)
15524  {
15525  // only allow the appropriate exit route to be searched
15526  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
15527  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
15528  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
15529  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
15530  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
15531  {
15532  InPrefDirFlag = true;
15533  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
15534  if(AutoSigsFlag)
15535  {
15536  StartElement1.AutoSignals = true;
15537  }
15538  StartElement1.PrefDirRoute = true;
15539  }
15540  }
15541  }
15542 
15543  if(!InPrefDirFlag)
15544  {
15545  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15546  Utilities->CallLogPop(205);
15547  return(false);
15548  }
15549 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
15551  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15552 
15553  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
15554  {
15555  throw Exception("Selection in two routes - should never happen!");
15556  }
15557  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
15558  {
15559  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15560  {
15561  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
15562  Utilities->CallLogPop(206);
15563  return(false);
15564  }
15565  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
15566  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15567  {
15568  TrainController->StopTTClockMessage(14, "No forward connection from this position");
15569  Utilities->CallLogPop(207);
15570  return(false);
15571  }
15572  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
15573  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15574  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15575  { //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
15576 // TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
15577 // Utilities->CallLogPop(208);
15578 // return(false);
15579  }
15580  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
15582  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
15583  if(AutoSigsFlag)
15584  {
15585  StartElement1.AutoSignals = true;
15586  }
15587  StartElement1.PrefDirRoute = true;
15589  Utilities->CallLogPop(209);
15590  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
15591  }
15592 
15593  else // no route started
15594  {
15595 // check if selected position is adjacent to start or end of an existing route and disallow
15596  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15597  {
15598  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
15599  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15600  {
15601  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
15602  Utilities->CallLogPop(210);
15603  return(false);
15604  }
15605  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15606  {
15607  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
15608  Utilities->CallLogPop(211);
15609  return(false);
15610  }
15611  }
15612 
15613 // check if it's adjacent to end of an existing route,
15614  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15615  {
15617  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15618  {
15619  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
15620  Utilities->CallLogPop(212);
15621  return(false);
15622  }
15623  }
15624  SearchVector.push_back(StartElement1);
15625  Utilities->CallLogPop(213);
15626  return(true);
15627  }
15628 }
15629 
15630 // ---------------------------------------------------------------------------
15631 
15632 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
15633  IDInt &ReqPosRouteID, bool &PointsChanged)
15634 
15635 /*
15636  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
15637 
15638  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
15639  this being set to -1 for not used.
15640  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
15641  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
15642  Check correct type of element - signal/buffers/continuation.
15643  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
15644  EndElement2 corresponding to the 2 possible PrefDir elements).
15645  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
15646  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
15647  linked forward to another route.
15648  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
15649  for same position as start should cover this)
15650 
15651  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
15652  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
15653  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
15654  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
15655  If the search fails then return false.
15656  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
15657  in the SearchVector to ensure it's entered as part of the new route.
15658  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
15659  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
15660  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
15661  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
15662  so return false, with an appropriate message if ConsecSignalsRoute set.
15663 */
15664 
15665 {
15666  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
15667  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
15668  int EndPosition; // the position selected
15669  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
15670 
15671  Track->LCFoundInAutoSigsRoute = false;
15673  TotalSearchCount = 0;
15674  ReqPosRouteID = IDInt(-1); // default value for not used
15675  TTrackElement TrackElement;
15676  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
15677  // given element as can't select 2-track elements
15678  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15679  {
15680  Utilities->CallLogPop(214);
15681  return(false);
15682  }
15683  if(Track->IsLCAtHV(19, HLoc, VLoc))
15684  {
15685  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
15686  Utilities->CallLogPop(1908);
15687  return(false);
15688  }
15689 // cancel selection if on original start element
15690  if(EndPosition == StartRoutePosition)
15691  {
15692  Utilities->CallLogPop(215);
15693  return(false);
15694  }
15695  if(AutoSigsFlag)
15696  {
15697  if(TrackElement.TrackType == Buffers)
15698  {
15699  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
15700  Utilities->CallLogPop(216);
15701  return(false);
15702  }
15703  }
15704  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15705  {
15706  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
15707  Utilities->CallLogPop(217);
15708  return(false);
15709  }
15710 // check if train on element
15711  if(TrackElement.TrainIDOnElement > -1)
15712  {
15713  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
15714  Utilities->CallLogPop(219);
15715  return(false);
15716  }
15717 // disallow if not in EveryPrefDir & set EndElement(s)
15718  bool InPrefDirFlag = false;
15719 
15720  bool FoundFlag;
15721  int PrefDirPos0 = -1;
15722  int PrefDirPos1 = -1;
15723  int PrefDirPos2 = -1;
15724  int PrefDirPos3 = -1;
15725 
15726  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
15727  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15728  int PrefDirVecPos[4] =
15729  {
15730  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15731  };
15732 
15733  for(int x = 0; x < 4; x++)
15734  {
15735  int b = PrefDirVecPos[x];
15736  if(b > -1)
15737  {
15738  InPrefDirFlag = true;
15739  if(EndElement1.TrackVectorPosition == -1)
15740  {
15741  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
15742  }
15743  else
15744  {
15745  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
15746  }
15747  }
15748  }
15749  if(!InPrefDirFlag)
15750  {
15751  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15752  Utilities->CallLogPop(220);
15753  return(false);
15754  }
15755 // check if in an existing route - can't be a bridge so can use a simple 'find'
15756 // bool InRoute = false;
15758  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15759 
15760  if(RoutePair.first > -1)
15761  {
15762  if(RoutePair.second != 0) // not first element in existing route so no good
15763  {
15764  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
15765  Utilities->CallLogPop(221);
15766  return(false);
15767  }
15768  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
15769 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15770  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
15771  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15772  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
15773  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15774  {
15775  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
15776  Utilities->CallLogPop(222);
15777  return(false);
15778  }
15779  EndElement1 = RouteElement;
15780  EndElement2 = BlankElement; // only need the route element
15781  EndPosition = EndElement1.TrackVectorPosition;
15782  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
15783  }
15784 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15785 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15786 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15787 
15788  if(EndElement1.HLoc >= StartElement1.HLoc)
15789  {
15791  SearchLimitHighH = EndElement1.HLoc + 15;
15792  }
15793  else
15794  {
15795  SearchLimitLowH = EndElement1.HLoc - 15;
15797  }
15798  if(EndElement1.VLoc >= StartElement1.VLoc)
15799  {
15801  SearchLimitHighV = EndElement1.VLoc + 15;
15802  }
15803  else
15804  {
15805  SearchLimitLowV = EndElement1.VLoc - 15;
15807  }
15808 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15809  check & TotalSearchCounts check
15810  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15811  {
15812  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
15813  Utilities->CallLogPop(1693);
15814  return false;
15815  }
15816 */
15817 // check if adjacent to start and disallow
15818  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15819  {
15821  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
15822 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
15823 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
15824  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15825  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15826  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
15827  {
15828  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
15829  Utilities->CallLogPop(223);
15830  return(false);
15831  }
15832 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15833 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15834  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15835  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15836  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15837  {
15838  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15839  Utilities->CallLogPop(224);
15840  return(false);
15841  }
15842 // check if adjacent to end of a route & disallow
15844  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15845  {
15846  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15847  Utilities->CallLogPop(225);
15848  return(false);
15849  }
15850  }
15851 
15852 // check for same route as start element
15854  {
15855  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15856  Utilities->CallLogPop(226);
15857  return(false);
15858  }
15859 // check for a looping route
15860  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15861  {
15863  {
15864  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15865  Utilities->CallLogPop(1844);
15866  return(false);
15867  }
15868  }
15869 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15870 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15871 // and don't want to add it again
15872  if(StartSelectionRouteID > -1)
15873  {
15874  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15875  AutoSigsFlag, false))
15876  {
15877  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15878  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15879  {
15880  if(NewFailedPointsTVPos > -1)
15881  {
15882  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15883  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15884  " failed during route setting.");
15885  Utilities->CallLogPop(2488);
15886  return(false);
15887  }
15888  PointsChanged = true;
15889  }
15890  Utilities->CallLogPop(227);
15891  return(true);
15892  }
15893  else if(!Track->SuppressRouteFailMessage)
15894  {
15895  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15897  Utilities->CallLogPop(228);
15898  return(false);
15899  }
15900  }
15901  else
15902  {
15903 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15904 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15905 
15906 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15907 // note that a blank element will have XLinkPos set to -1
15908  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15909  {
15910  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15911  AutoSigsFlag, false))
15912  {
15913  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15914  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15915  {
15916  if(NewFailedPointsTVPos > -1)
15917  {
15918  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15919  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15920  " failed during route setting.");
15921  Utilities->CallLogPop(2490);
15922  return(false);
15923  }
15924  PointsChanged = true;
15925  }
15926  Utilities->CallLogPop(229);
15927  return(true);
15928  }
15929  else
15930  {
15932  {
15934  }
15935  Utilities->CallLogPop(230);
15936  return(false);
15937  }
15938  }
15939  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15940  {
15941  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15942  AutoSigsFlag, false))
15943  {
15944  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15945  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15946  {
15947  if(NewFailedPointsTVPos > -1)
15948  {
15949  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15950  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15951  " failed during route setting.");
15952  Utilities->CallLogPop(2492);
15953  return(false);
15954  }
15955  PointsChanged = true;
15956  }
15957  Utilities->CallLogPop(231);
15958  return(true);
15959  }
15960  else
15961  {
15963  {
15965  }
15966  Utilities->CallLogPop(232);
15967  return(false);
15968  }
15969  }
15970  // now start off in the best direction
15971  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15972  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15973  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15974  // unless new problems are found.
15975  if(StartElement1.XLinkPos == BestPos)
15976  {
15977  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15978  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15979  AutoSigsFlag, false))
15980  {
15981  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15982  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15983  {
15984  if(NewFailedPointsTVPos > -1)
15985  {
15986  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15987  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15988  " failed during route setting.");
15989  Utilities->CallLogPop(2494);
15990  return(false);
15991  }
15992  PointsChanged = true;
15993  }
15994  Utilities->CallLogPop(233);
15995  return(true);
15996  }
15997  else if(StartElement2.TrackVectorPosition > -1)
15998  {
15999  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16000  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16001  AutoSigsFlag, false))
16002  {
16003  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
16004  if(PointsToBeChanged(9, NewFailedPointsTVPos))
16005  {
16006  if(NewFailedPointsTVPos > -1)
16007  {
16008  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
16009  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
16010  " failed during route setting.");
16011  Utilities->CallLogPop(2496);
16012  return(false);
16013  }
16014  PointsChanged = true;
16015  }
16016  Utilities->CallLogPop(234);
16017  return(true);
16018  }
16019  }
16020  }
16021  else if(StartElement2.TrackVectorPosition > -1)
16022  {
16023  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16024  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16025  AutoSigsFlag, false))
16026  {
16027  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
16028  if(PointsToBeChanged(10, NewFailedPointsTVPos))
16029  {
16030  if(NewFailedPointsTVPos > -1)
16031  {
16032  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
16033  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
16034  " failed during route setting.");
16035  Utilities->CallLogPop(2498);
16036  return(false);
16037  }
16038  PointsChanged = true;
16039  }
16040  Utilities->CallLogPop(1857);
16041  return(true);
16042  }
16043  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16044  AutoSigsFlag, false))
16045  {
16046  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
16047  if(PointsToBeChanged(11, NewFailedPointsTVPos))
16048  {
16049  if(NewFailedPointsTVPos > -1)
16050  {
16051  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
16052  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
16053  " failed during route setting.");
16054  Utilities->CallLogPop(2500);
16055  return(false);
16056  }
16057  PointsChanged = true;
16058  }
16059  Utilities->CallLogPop(1858);
16060  return(true);
16061  }
16062  }
16063  else if(StartElement1.XLinkPos == (1 - BestPos))
16064  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
16065  {
16066  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16067  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16068  AutoSigsFlag, false))
16069  {
16070  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
16071  if(PointsToBeChanged(12, NewFailedPointsTVPos))
16072  {
16073  if(NewFailedPointsTVPos > -1)
16074  {
16075  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
16076  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
16077  " failed during route setting.");
16078  Utilities->CallLogPop(2502);
16079  return(false);
16080  }
16081  PointsChanged = true;
16082  }
16083  Utilities->CallLogPop(1864);
16084  return(true);
16085  }
16086  }
16087  }
16089  {
16091  }
16092  Utilities->CallLogPop(235);
16093  return(false);
16094 }
16095 
16096 // ---------------------------------------------------------------------------
16097 
16098 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
16099 {
16100  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
16101  if(PrefDirSize() == 0)
16102  {
16103  Utilities->CallLogPop(1704);
16104  return;
16105  }
16106  for(unsigned int x = 0; x < PrefDirSize(); x++)
16107  {
16108  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
16109  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
16110  {
16111  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16112  TempPrefDirElement.EXGraphicPtr);
16113  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
16114  {
16115  if(x == 0)
16116  {
16117  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16118  TempPrefDirElement.EntryDirectionGraphicPtr);
16119  }
16120  if(x == (PrefDirSize() - 1))
16121  {
16122  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16123  TempPrefDirElement.EntryDirectionGraphicPtr);
16124  }
16125  }
16126  }
16127  }
16128 
16129  Utilities->CallLogPop(1705);
16130 }
16131 
16132 // ---------------------------------------------------------------------------
16133 
16134 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
16135  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
16136 /*
16137  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
16138  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
16139  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
16140  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
16141  Return false if any element (apart from RequiredPosition) is on an existing route.
16142  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
16143 
16144  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
16145  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
16146  added during the function so as to leave it exactly as it was on entering, then return false).
16147  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
16148  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
16149  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
16150  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
16151  the route number that the searched-for element is the start of if any, and set to -1 if no
16152  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
16153  this unit, together with the ConsecSignals and AutoSigsFlag flags.
16154  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
16155  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
16156 
16157  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
16158  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
16159  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
16160  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
16161  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
16162  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
16163  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16164  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
16165  or if train on element (unless a bridge & train on different track).
16166  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
16167  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
16168  a leading point where both trailing directions are in EveryPrefDir, if not fail.
16169  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
16170  AutoSignals member set if AutoSigsFlag set, then return true.
16171  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
16172 
16173  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
16174  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
16175  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
16176  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
16177  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
16178  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
16179  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
16180 
16181  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
16182  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
16183 */
16184 
16185 {
16186  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
16187  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
16188  AnsiString((short)AutoSigsFlag) + "," + AnsiString((short)RecursiveCall));
16189  int VectorCount = 0;
16190  if(!RecursiveCall) //added at v2.15.1
16191  {
16193  }
16194 
16195  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
16196 
16197 // check for a fouled diagonal for first element. Added for v1.3.2
16198  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
16199  {
16200  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
16201  {
16202  for(int x = 0; x < VectorCount; x++)
16203  {
16204  SearchVector.erase(SearchVector.end() - 1);
16205  }
16206  Utilities->CallLogPop(2043);
16207  return(false);
16208  }
16209  }
16210  bool FirstPass = true;
16211 
16212  while(true)
16213  {
16214  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
16215  {
16216  Track->LCFoundInAutoSigsRoute = true;
16217  }
16218  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
16219  {
16220  for(int x = 0; x < VectorCount; x++)
16221  {
16222  SearchVector.erase(SearchVector.end() - 1);
16223  }
16224  Utilities->CallLogPop(1926);
16225  return(false);
16226  }
16227  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
16228  {
16229  for(int x = 0; x < VectorCount; x++)
16230  {
16231  SearchVector.erase(SearchVector.end() - 1);
16232  }
16233  Utilities->CallLogPop(236);
16234  return(false);
16235  }
16236  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
16237  // reached a valid signal that isn't the required position, user should always select the next
16238  // signal in a route when ConsecSignals is true so have to fail
16239  // won't affect recurive searches as for them the first pass element is always a point
16240  {
16241  for(int x = 0; x < VectorCount; x++)
16242  {
16243  SearchVector.erase(SearchVector.end() - 1);
16244  }
16245  Utilities->CallLogPop(237);
16246  return(false);
16247  }
16248  FirstPass = false;
16249  int NextPosition = PrefDirElement.Conn[XLinkPos];
16250  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
16251  TPrefDirElement SearchElement(NextTrackElement);
16252  SearchElement.TrackVectorPosition = NextPosition;
16253  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
16254  SearchElement.ELinkPos = NextELinkPos;
16255  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
16256  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
16257  int NextXLinkPos;
16258  if(SearchElement.ELinkPos == 0)
16259  {
16260  NextXLinkPos = 1;
16261  }
16262  if(SearchElement.ELinkPos == 1)
16263  {
16264  NextXLinkPos = 0;
16265  }
16266  if(SearchElement.ELinkPos == 2)
16267  {
16268  NextXLinkPos = 3;
16269  }
16270  if(SearchElement.ELinkPos == 3)
16271  {
16272  NextXLinkPos = 2;
16273  }
16274  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16275  {
16276  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16277 // note that may be buffers, continuation or gap
16278  SearchElement.XLinkPos = NextXLinkPos;
16279  }
16280 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
16281 
16282 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16283  drop this at v2.16.1 as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of points and
16284  crossovers as can reach element on opposite track and still find the required end point - causes error when adding to the Route2MultiMap
16285  (happened by chance when developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search
16286  through all searchvector.
16287 
16288  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
16289 */
16290  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
16291  {
16292  for(unsigned int x = 0; x < SearchVector.size(); x++)
16293  {
16294  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
16295  {
16296  for(int x = 0; x < VectorCount; x++)
16297  {
16298  SearchVector.erase(SearchVector.end() - 1);
16299  }
16300  Utilities->CallLogPop(2653);
16301  return(false);
16302  }
16303  }
16304  }
16305  else if(SearchElement.TrackType == Bridge)
16306  {
16307  for(unsigned int x = 0; x < SearchVector.size(); x++)
16308  {
16309  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
16310  (SearchElement.ELink == SearchVector.at(x).ELink))
16311  {
16312  for(int x = 0; x < VectorCount; x++)
16313  {
16314  SearchVector.erase(SearchVector.end() - 1);
16315  }
16316  Utilities->CallLogPop(2654);
16317  return(false);
16318  }
16319  }
16320  }
16321 
16322 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16323  TAllRoutes::TRouteElementPair SecondPair;
16325  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16326  if(RoutePair.first > -1)
16327  {
16328  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16329  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
16330  RoutePair.second).ELinkPos)))
16331  {
16332  // still OK if start of an expected route
16333  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
16334  {
16335  for(int x = 0; x < VectorCount; x++)
16336  {
16337  SearchVector.erase(SearchVector.end() - 1);
16338  }
16339  Utilities->CallLogPop(239);
16340  return(false); // only allow for start of an expected route
16341  }
16342  }
16343  }
16344  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16345  {
16346  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16347  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
16348  SecondPair.second).ELinkPos)))
16349  {
16350  // still OK if start of an expected route
16351  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
16352  {
16353  for(int x = 0; x < VectorCount; x++)
16354  {
16355  SearchVector.erase(SearchVector.end() - 1);
16356  }
16357  Utilities->CallLogPop(240);
16358  return(false); // only allow for start of an expected route
16359  }
16360  }
16361  }
16362 // check if a train on element, unless a bridge & train on different track
16363 // OK of same train as start element - no drop this
16364 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16365  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16366  {
16367  for(int x = 0; x < VectorCount; x++)
16368  {
16369  SearchVector.erase(SearchVector.end() - 1);
16370  }
16371  Utilities->CallLogPop(241);
16372  return(false);
16373  }
16374  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16375  {
16376  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16377  {
16378  for(int x = 0; x < VectorCount; x++)
16379  {
16380  SearchVector.erase(SearchVector.end() - 1);
16381  }
16382  Utilities->CallLogPop(242);
16383  return(false);
16384  }
16385  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16386  {
16387  for(int x = 0; x < VectorCount; x++)
16388  {
16389  SearchVector.erase(SearchVector.end() - 1);
16390  }
16391  Utilities->CallLogPop(243);
16392  return(false);
16393  }
16394  }
16395 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
16396  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16397  {
16398  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16399  {
16400  for(int x = 0; x < VectorCount; x++)
16401  {
16402  SearchVector.erase(SearchVector.end() - 1);
16403  }
16404  Utilities->CallLogPop(244);
16405  return(false);
16406  }
16407  }
16408 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
16409 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
16410  bool InPrefDirFlag = false;
16411  PrefDirElement1 = BlankElement;
16412  PrefDirElement2 = BlankElement;
16413 
16414  bool FoundFlag;
16415  int PrefDirPos0 = -1;
16416  int PrefDirPos1 = -1;
16417  int PrefDirPos2 = -1;
16418  int PrefDirPos3 = -1;
16420  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
16421  int PrefDirVecPos[4] =
16422  {
16423  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
16424  };
16425  for(int x = 0; x < 4; x++)
16426  {
16427  int b = PrefDirVecPos[x];
16428  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
16429  {
16430  InPrefDirFlag = true;
16431  if(PrefDirElement1.TrackVectorPosition == -1)
16432  {
16433  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
16434  }
16435  else
16436  {
16437  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
16438  }
16439  }
16440  }
16441  if(!InPrefDirFlag)
16442  {
16443  for(int x = 0; x < VectorCount; x++)
16444  {
16445  SearchVector.erase(SearchVector.end() - 1);
16446  }
16447  Utilities->CallLogPop(245);
16448  return(false);
16449  }
16450 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16451 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16452 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16454  {
16455  for(int x = 0; x < VectorCount; x++)
16456  {
16457  SearchVector.erase(SearchVector.end() - 1);
16458  }
16459  Utilities->CallLogPop(1690);
16460  return(false);
16461  }
16462 // check if found it
16463  if(SearchElement.TrackVectorPosition == RequiredPosition)
16464  {
16465 // need to ensure a signal/buffer/continuation
16466 // if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End)) dropped at v2.16.1 - may find element round a loop and appear invalid when in fact valid
16467  if((SearchElement.TrackType != SignalPost) && (SearchElement.TrackType != Buffers) && (SearchElement.TrackType != Continuation)) //added at v2.16.1
16468  {
16469  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
16471  for(int x = 0; x < VectorCount; x++)
16472  {
16473  SearchVector.erase(SearchVector.end() - 1);
16474  }
16475  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1 (to stop several same messages being given)
16476  Utilities->CallLogPop(246);
16477  return(false);
16478  } // if((SearchElement.TrackType != SignalPost) &&.......
16479 //need to make sure it's in the right direction
16480  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
16481  { //condition added at v2.16.1
16482  for(int x = 0; x < VectorCount; x++)
16483  {
16484  SearchVector.erase(SearchVector.end() - 1);
16485  }
16486  Utilities->CallLogPop(2627);
16487  return(false);
16488  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal)......
16489 
16490  if(AutoSigsFlag)
16491  {
16492  PrefDirElement1.AutoSignals = true;
16493  }
16494  PrefDirElement1.PrefDirRoute = true;
16496  {
16498  {
16499  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
16501  }
16502  for(int x = 0; x < VectorCount; x++)
16503  {
16504  SearchVector.erase(SearchVector.end() - 1);
16505  }
16506  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1
16507  Utilities->CallLogPop(1928);
16508  return(false);
16509  }
16510  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
16511  VectorCount++; // not really needed but include for tidyness
16512  TotalSearchCount++;
16513  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0. SignalHasFailed returns true if a signal somewhere on the route fails, route not set if so
16514  { //has to be the top level call (!RecursiveCall) as only then is the route sue to be set
16515  for(int x = 0; x < VectorCount; x++)
16516  {
16517  SearchVector.erase(SearchVector.end() - 1);
16518  }
16519  Utilities->CallLogPop(2522);
16520  return(false);
16521  }
16522  Utilities->CallLogPop(247);
16523  return(true);
16524  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
16525 
16526 // check if a buffer or continuation (end of search on this leg if not found by now)
16527  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16528  {
16529  for(int x = 0; x < VectorCount; x++)
16530  {
16531  SearchVector.erase(SearchVector.end() - 1);
16532  }
16533  Utilities->CallLogPop(248);
16534  return(false);
16535  }
16536 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
16538  {
16539  for(int x = 0; x < VectorCount; x++)
16540  {
16541  SearchVector.erase(SearchVector.end() - 1);
16542  }
16543  Utilities->CallLogPop(1420);
16544  return(false);
16545  }
16546 //deal with failed points, added at v2.13.0
16547  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
16548  {
16549  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
16550  {
16551  SearchElement.XLinkPos = 1;
16552  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16553  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16554  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16555  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16556  }
16557  else
16558  {
16559  SearchElement.XLinkPos = 3;
16560  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16561  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16562  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16563  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16564  }
16565  }
16566  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
16567  {
16568  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16569  {
16570  for(int x = 0; x < VectorCount; x++)
16571  {
16572  SearchVector.erase(SearchVector.end() - 1);
16573  }
16574  Utilities->CallLogPop(2514);
16575  return(false);
16576  }
16577  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16578  {
16579  for(int x = 0; x < VectorCount; x++)
16580  {
16581  SearchVector.erase(SearchVector.end() - 1);
16582  }
16583  Utilities->CallLogPop(2515);
16584  return(false);
16585  }
16586  }
16587 // check if reached a non-failed leading point
16588  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
16589  {
16590 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16591  int SearchPos1 = SearchElement.Attribute + 1;
16592  int SearchPos2;
16593  if(SearchPos1 == 2)
16594  {
16595  SearchPos1++;
16596  }
16597  if(SearchPos1 == 1)
16598  {
16599  SearchPos2 = 3;
16600  }
16601  else
16602  {
16603  SearchPos2 = 1;
16604  }
16605  SearchElement.XLink = SearchElement.Link[SearchPos1];
16606  SearchElement.XLinkPos = SearchPos1;
16607  InPrefDirFlag = false;
16608  if(SearchElement.XLink == PrefDirElement1.XLink)
16609  {
16610  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16611  InPrefDirFlag = true;
16612  }
16613  else if(SearchElement.XLink == PrefDirElement2.XLink)
16614  {
16615  SearchElement = PrefDirElement2;
16616  InPrefDirFlag = true;
16617  }
16618 // push element with XLink set to position [SearchPos1] if on a PrefDir
16619  if(InPrefDirFlag)
16620  {
16621 // check for a fouled diagonal for leading point for XLinkPos == 1)
16622  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16623  {
16624  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16625  {
16626  for(int x = 0; x < VectorCount; x++)
16627  {
16628  SearchVector.erase(SearchVector.end() - 1);
16629  }
16630  Utilities->CallLogPop(249);
16631  return(false);
16632  }
16633  }
16634  if(AutoSigsFlag)
16635  {
16636  SearchElement.AutoSignals = true;
16637  }
16638  SearchElement.PrefDirRoute = true;
16639  SearchVector.push_back(SearchElement);
16640  VectorCount++;
16641  TotalSearchCount++;
16642 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16643  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16644  AutoSigsFlag, true))
16645  {
16647  {
16649  {
16650  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
16652  }
16653  for(int x = 0; x < VectorCount; x++)
16654  {
16655  SearchVector.erase(SearchVector.end() - 1);
16656  }
16657  Utilities->CallLogPop(1929);
16658  return(false);
16659  }
16660  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
16661  {
16662  for(int x = 0; x < VectorCount; x++)
16663  {
16664  SearchVector.erase(SearchVector.end() - 1);
16665  }
16666  Utilities->CallLogPop(2523);
16667  return(false);
16668  }
16669  Utilities->CallLogPop(250);
16670  return(true);
16671  }
16672  else
16673  {
16674 // remove leading point with XLinkPos [1]
16675  if(!QuitAllRecursiveSearchesFlag) //added at v2.15.1
16676  {
16677  SearchVector.erase(SearchVector.end() - 1);
16678  VectorCount--;
16679  }
16680  else
16681  {
16682  for(int x = 0; x < VectorCount; x++)
16683  {
16684  SearchVector.erase(SearchVector.end() - 1);
16685  }
16686  Utilities->CallLogPop(2626);
16687  return(false);
16688  }
16689  }
16690  }
16691 // XLink set to position [SearchPos2]
16692  SearchElement.XLink = SearchElement.Link[SearchPos2];
16693  SearchElement.XLinkPos = SearchPos2;
16694  if(SearchElement.XLink == PrefDirElement1.XLink)
16695  {
16696  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16697  }
16698  else if(SearchElement.XLink == PrefDirElement2.XLink)
16699  {
16700  SearchElement = PrefDirElement2;
16701  }
16702  else // failed to find a valid exit from the point
16703  {
16704  for(int x = 0; x < VectorCount; x++)
16705  {
16706  SearchVector.erase(SearchVector.end() - 1);
16707  }
16708  Utilities->CallLogPop(251);
16709  return(false);
16710  }
16711 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16712  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16713  {
16714  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16715  {
16716  for(int x = 0; x < VectorCount; x++)
16717  {
16718  SearchVector.erase(SearchVector.end() - 1);
16719  }
16720  Utilities->CallLogPop(252);
16721  return(false);
16722  }
16723  }
16724 // push element with XLink set to position [SearchPos2]
16725  if(AutoSigsFlag)
16726  {
16727  SearchElement.AutoSignals = true;
16728  }
16729  SearchElement.PrefDirRoute = true;
16730  SearchVector.push_back(SearchElement);
16731  VectorCount++;
16732  TotalSearchCount++;
16733 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16734  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16735  AutoSigsFlag, true))
16736  {
16738  {
16740  {
16741  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
16743  }
16744  for(int x = 0; x < VectorCount; x++)
16745  {
16746  SearchVector.erase(SearchVector.end() - 1);
16747  }
16748  Utilities->CallLogPop(1930);
16749  return(false);
16750  }
16751  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
16752  {
16753  for(int x = 0; x < VectorCount; x++)
16754  {
16755  SearchVector.erase(SearchVector.end() - 1);
16756  }
16757  Utilities->CallLogPop(2524);
16758  return(false);
16759  }
16760  Utilities->CallLogPop(1592);
16761  return(true);
16762  }
16763  else
16764  {
16765  for(int x = 0; x < VectorCount; x++)
16766  {
16767  SearchVector.erase(SearchVector.end() - 1);
16768  }
16769  Utilities->CallLogPop(253);
16770  return(false);
16771  }
16772  } // if leading point
16773 
16774 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
16775  SearchElement = PrefDirElement1;
16776  if(AutoSigsFlag)
16777  {
16778  SearchElement.AutoSignals = true;
16779  }
16780  SearchElement.PrefDirRoute = true;
16781  SearchVector.push_back(SearchElement);
16782  VectorCount++;
16783  TotalSearchCount++;
16784  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16785  PrefDirElement = SearchElement;
16786  } // while(true)
16787 }
16788 
16789 // ---------------------------------------------------------------------------
16790 
16791 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
16792 {
16793 /*
16794  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
16795  and the new or extended route created from that. Hence action varies depending on whether
16796  it is a completely new route, or an extension of an existing route at the beginning or the end.
16797  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16798  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16799 
16800  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16801  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
16802  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
16803  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
16804  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
16805  is decremented;
16806  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
16807  from the existing route, then enter the new route into the AllRoutesVector;
16808  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16809  then enter the new route into the AllRoutesVector.
16810 
16811  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
16812  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
16813  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
16814  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
16815  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16816  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
16817  for the new route and return;
16818  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
16819  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
16820 
16821  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
16822  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
16823  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
16824 
16825 */
16826  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
16827  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
16828  if(SearchVector.size() < 1)
16829  {
16830  Utilities->CallLogPop(254);
16831  return;
16832  }
16834  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
16835  {
16836  Utilities->CallLogPop(255);
16837  return;
16838  }
16839  TAllRoutes::TLockedRouteClass LockedRouteObject;
16840 
16842  unsigned int TruncatePrefDirPosition = 0;
16843 
16844  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
16845 /* if have ReqPosRouteID:
16846  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
16847  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
16848  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
16849  the existing route, then enter the new route into the AllRoutesVector
16850  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16851  then enter the new route into the AllRoutesVector
16852 */
16853  {
16856  {
16857  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
16858  x++) // start at 1 as first element already in SearchVector
16859  {
16861  }
16862  // note that route numbers in map adjusted when ReqPos route cleared
16864  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16865  // set during ClearRouteDuringRouteBuildingAt
16867  {
16870  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16871  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16872  }
16873  }
16875  {
16877  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16878  }
16880  {
16881  SearchVector.pop_back();
16882  }
16883  }
16884  if(StartSelectionRouteID > -1)
16885 /* if have StartSelectionRouteID:
16886  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16887  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
16888  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16889  then add it to the start of the new route, then enter the new route into the AllRoutesVector
16890  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16891 */
16892  {
16894  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16895  {
16898  {
16899  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
16900  for(unsigned int x = 0; x < SearchVector.size(); x++)
16901  {
16903  RouteNumber, GetFixedSearchElementAt(3, x));
16904  // find & store locked route truncate position in PrefDirVector for later use
16906  {
16907  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
16908  {
16909  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
16910  }
16911  }
16912  }
16914  {
16915  throw Exception("Error - failed to validate extended route for preferred route");
16916  }
16919  if(!AutoSigsFlag)
16920  {
16921  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
16922  }
16923  // now add the reinstated locked route if required and set signals accordingly
16925  {
16926  LockedRouteObject.RouteNumber = RouteNumber;
16927  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16928  // now reset the signals for the locked route
16929  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16930  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16931  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16932  {
16933  // return all signals to red in route section to be truncated
16934  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16935  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16936  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16937  {
16938  TrackElement.Attribute = 0;
16939  Track->PlotSignal(10, TrackElement, Display);
16940  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16941  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16942  }
16943  }
16944  }
16945  AllRoutes->CheckMapAndRoutes(1); // test
16946  Utilities->CallLogPop(256);
16947  return;
16948  }
16950  {
16953  RouteElement.AutoSignals = true;
16954  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16955  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16956  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16957  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16958  }
16959  }
16960  else
16961  {
16963  }
16964 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16965 // AllRoutesVector hence nothing to do here
16966  }
16967  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16968  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16969  {
16970  throw Exception("Error - failed to validate single route for preferred route");
16971  }
16972  AllRoutes->StoreOneRoute(1, this);
16973  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16974  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16975  if(!AutoSigsFlag)
16976  {
16977  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16978  }
16979  AllRoutes->CheckMapAndRoutes(2); // test
16980  Utilities->CallLogPop(257);
16981 }
16982 
16983 // ---------------------------------------------------------------------------
16984 
16985 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16986 {
16987 /*
16988  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16989  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16990  & ensure signal/buffers/continuation.
16991  Note that can't select ConsecSignalsRoute for non-preferred routes.
16992  Check if train on element & disallow.
16993  Set default values for retained parameters:-
16994  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16995  StartSelectionRouteID = route that selection starts in if there is one;
16996 
16997  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16998  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16999  validity. This is just for safety reasons, the PrefDir values aren't used.
17000  StartElement1 & 2 are set to these PrefDirelements.
17001 
17002  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
17003 
17004  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
17005  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
17006  blank StartElement2 (only want to use the route element), then return true.
17007  Check if adjacent to start or end of an existing route & disallow if so.
17008  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
17009  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
17010  SetRemainingSearchVectorValues().
17011  Finally add the required element to the SearchVector & return true.
17012 
17013 */
17014  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
17015  AnsiString(VLoc) + "," + AnsiString((short)Callon));
17016  ClearRoute();
17017  int TrackVectorPosition;
17018  TTrackElement TrackElement;
17019  TPrefDirElement FirstElement, LastElement;
17020 
17021  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
17022  {
17023  Utilities->CallLogPop(258);
17024  return(false);
17025  }
17026  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
17027  {
17028  if(!Callon)
17029  {
17030  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
17031  }
17032 // makes later adjacent route checks too complicated
17033  Utilities->CallLogPop(259);
17034  return(false);
17035  }
17036  if(Track->IsLCAtHV(21, HLoc, VLoc))
17037  {
17038  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
17039  Utilities->CallLogPop(1910);
17040  return(false);
17041  }
17042 // check if selected a train & disallow if so
17043  if(TrackElement.TrainIDOnElement > -1)
17044  {
17045  if(!Callon)
17046  {
17047  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
17048  }
17049  Utilities->CallLogPop(260);
17050  return(false);
17051  }
17052 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
17053  TPrefDirElement PrefDirElement;
17054  int LockedVectorNumber;
17055 
17056  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
17057  {
17058  if(!Callon)
17059  {
17060  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
17061  }
17062  Utilities->CallLogPop(261);
17063  return(false);
17064  }
17065  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
17066  {
17067  if(!Callon)
17068  {
17069  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
17070  }
17071  Utilities->CallLogPop(262);
17072  return(false);
17073  }
17075 // AdjacentStartRouteNumber = -1;
17076  StartRoutePosition = TrackVectorPosition;
17077 // StartRouteSelectPosition = TrackVectorPosition;
17078 
17079  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17080  TPrefDirElement PrefDirElement2(TrackElement);
17081 
17082  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
17083  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
17084  TPrefDirElement BlankElement;
17085 
17086  PrefDirElement1.ELinkPos = 0;
17087  PrefDirElement1.XLinkPos = 1;
17088  PrefDirElement1.ELink = PrefDirElement1.Link[0];
17089  PrefDirElement1.XLink = PrefDirElement1.Link[1];
17090  if(!(PrefDirElement1.EntryExitNumber()))
17091  {
17092  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
17093  // no need for bridge check as bridge selections not allowed
17094  }
17095  PrefDirElement1.CheckCount = 9;
17096  PrefDirElement2.ELinkPos = 1;
17097  PrefDirElement2.XLinkPos = 0;
17098  PrefDirElement2.ELink = PrefDirElement2.Link[1];
17099  PrefDirElement2.XLink = PrefDirElement2.Link[0];
17100  if(!(PrefDirElement2.EntryExitNumber()))
17101  {
17102  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
17103  }
17104  PrefDirElement2.CheckCount = 9; // both now set
17105 
17106 // set StartElements to the above PrefDirElements
17107  StartElement1 = PrefDirElement1;
17108  StartElement2 = PrefDirElement2;
17109 
17110 // no PrefDir check needed as doesn't need to be in a PrefDir
17111 
17112 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
17114  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17115 
17116  if(RoutePair.first > -1)
17117  {
17118  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
17119  {
17120  if(!Callon)
17121  {
17122  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
17123  }
17124  Utilities->CallLogPop(263);
17125  return(false);
17126  }
17127  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
17128  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
17129  {
17130  if(!Callon)
17131  {
17132  TrainController->StopTTClockMessage(39, "No forward connection from this position");
17133  }
17134  Utilities->CallLogPop(264);
17135  return(false);
17136  }
17137  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
17138  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
17139  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17140  {
17141 // if(!Callon) //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
17142 // {
17143 // TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
17144 // }
17145 // Utilities->CallLogPop(265);
17146 // return(false);
17147  }
17148  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
17150  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
17151  StartElement2 = BlankElement; // only use the route element
17153  Utilities->CallLogPop(266);
17154  return(true); // all retained values set
17155  }
17156 
17157  else // selection not in an existing route
17158  {
17159 // check if it's adjacent to start of an an existing route,
17160  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17161  {
17162  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
17163  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
17164  {
17165  if(!Callon)
17166  {
17167  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
17168  }
17169  Utilities->CallLogPop(267);
17170  return(false);
17171  }
17172  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
17173  {
17174  if(!Callon)
17175  {
17176  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
17177  }
17178  Utilities->CallLogPop(268);
17179  return(false);
17180  }
17181  }
17182 // check if it's adjacent to end of an an existing route,
17183  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17184  {
17186  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
17187  {
17188  if(!Callon)
17189  {
17190  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
17191  }
17192  Utilities->CallLogPop(269);
17193  return(false);
17194  }
17195  }
17196  // not in a route or adjacent to start or end of a route
17197  // in this case reset all variable values to -1 & CheckCount to 4
17198  StartElement1.ELink = -1;
17199  StartElement1.ELinkPos = -1;
17200  StartElement1.XLink = -1;
17201  StartElement1.XLinkPos = -1;
17202  StartElement1.EXNumber = -1;
17203  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
17204  StartElement2 = BlankElement;
17205  SearchVector.push_back(StartElement1);
17206  Utilities->CallLogPop(270);
17207  return(true);
17208  }
17209 }
17210 
17211 // ---------------------------------------------------------------------------
17212 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
17213 
17214 /*
17215  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
17216 
17217  Declare the following integers:-
17218  EndPosition - TrackVectorPosition for the selection;
17219  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
17220  Check if selection is a valid track element and set EndPosition.
17221  Cancel if select original start element, then check that not points, bridge or crossover.
17222  Check & fail if a train is present at the selection.
17223  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
17224  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
17225  No check needed for selection in EveryPrefDir.
17226  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
17227  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
17228  as don't need it if in a route.
17229  Check if selection adj to start or end of a route and disallow.
17230  Fail if select same route as starting route, though should already have failed earlier if this is so.
17231 
17232  If there's a StartSelectionRouteID then StartElement1 will be set to
17233  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
17234  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
17235  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
17236  to add the new route to the AllRoutesVectorPtr.
17237  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
17238  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
17239  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
17240  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
17241  the search vector values and return.
17242  If not returned yet then have failed to find the required element so return false with no message.
17243 
17244 */
17245 
17246 {
17247 // get EndPosition
17248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
17249  AnsiString(VLoc));
17250  int EndPosition;
17251  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
17252 
17253  TotalSearchCount = 0;
17254  ReqPosRouteID = IDInt(-1); // for not used
17255  TTrackElement TrackElement;
17256  TPrefDirElement BlankElement;
17258 
17259  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
17260  {
17261  Utilities->CallLogPop(271);
17262  return(false);
17263  }
17264 // EndPosition = EndSelectPosition;
17265 // cancel selection if on original start element
17266  if(EndPosition == StartRoutePosition)
17267  {
17268  Utilities->CallLogPop(272);
17269  return(false);
17270  }
17271  if(Track->IsLCAtHV(22, HLoc, VLoc))
17272  {
17273  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
17274  Utilities->CallLogPop(1911);
17275  return(false);
17276  }
17277  if((TrackElement.TrackType == Points) && !Callon)
17278  {
17279  if(!Callon)
17280  {
17281  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
17282  }
17283 // makes later adjacent route checks too complicated
17284  Utilities->CallLogPop(273);
17285  return(false);
17286  }
17287  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
17288  {
17289  if(!Callon)
17290  {
17291  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
17292  }
17293 // makes later adjacent route checks too complicated
17294  Utilities->CallLogPop(1861);
17295  return(false);
17296  }
17297 // check if train on element
17298  if(TrackElement.TrainIDOnElement > -1)
17299  {
17300  if(!Callon)
17301  {
17302  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
17303  }
17304  Utilities->CallLogPop(274);
17305  return(false);
17306  }
17307 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
17308 // check passed)
17309  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17310  TPrefDirElement EndElement2(TrackElement);
17311 
17312  EndElement1.TrackVectorPosition = EndPosition;
17313  EndElement2.TrackVectorPosition = EndPosition;
17314  EndElement1.ELinkPos = 0;
17315  EndElement1.XLinkPos = 1;
17316  EndElement1.ELink = EndElement1.Link[0];
17317  EndElement1.XLink = EndElement1.Link[1];
17318  if(!(EndElement1.EntryExitNumber()))
17319  {
17320  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
17321  }
17322  EndElement1.CheckCount = 9;
17323  EndElement2.ELinkPos = 1;
17324  EndElement2.XLinkPos = 0;
17325  EndElement2.ELink = EndElement2.Link[1];
17326  EndElement2.XLink = EndElement2.Link[0];
17327  if(!(EndElement2.EntryExitNumber()))
17328  {
17329  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
17330  }
17331  EndElement2.CheckCount = 9; // both now set
17332 
17333 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
17334 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
17335 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
17336 
17337  if(EndElement1.HLoc >= StartElement1.HLoc)
17338  {
17340  SearchLimitHighH = EndElement1.HLoc + 15;
17341  }
17342  else
17343  {
17344  SearchLimitLowH = EndElement1.HLoc - 15;
17346  }
17347  if(EndElement1.VLoc >= StartElement1.VLoc)
17348  {
17350  SearchLimitHighV = EndElement1.VLoc + 15;
17351  }
17352  else
17353  {
17354  SearchLimitLowV = EndElement1.VLoc - 15;
17356  }
17357 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
17358  check & TotalSearchCounts check
17359  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
17360  {
17361  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
17362  Utilities->CallLogPop(1694);
17363  return false;
17364  }
17365 */
17366 // don't need EveryPrefDir check for NonPreferredRoute
17367 
17368 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
17369 // bool InRoute = false;
17371  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17372 
17373  if(RoutePair.first > -1)
17374  {
17375  if(RoutePair.second != 0) // not first element in existing route so no good
17376  {
17377  if(!Callon)
17378  {
17379  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
17380  }
17381  Utilities->CallLogPop(275);
17382  return(false);
17383  }
17384  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
17385 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
17386  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
17387  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
17388  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17389  {
17390  if(!Callon)
17391  {
17392  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
17393  }
17394  Utilities->CallLogPop(276);
17395  return(false);
17396  }
17397  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
17398  EndElement2 = BlankElement; // only need the route element
17399  EndPosition = EndElement1.TrackVectorPosition;
17400  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
17401  }
17402 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
17403  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17404  {
17405  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
17406  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
17407 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17408 // && (AdjPosition != StartRoutePosition))
17409  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17410  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17411  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
17412  {
17413  if(!Callon)
17414  {
17415  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
17416  }
17417  Utilities->CallLogPop(277);
17418  return(false);
17419  }
17420 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
17421 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
17422  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
17423  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17424  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
17425  (AdjPosition != StartRoutePosition))
17426  {
17427  if(!Callon)
17428  {
17429  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
17430  }
17431  Utilities->CallLogPop(278);
17432  return(false);
17433  }
17434 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
17436  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
17437  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
17438  {
17439  if(!Callon)
17440  {
17441  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
17442  }
17443  Utilities->CallLogPop(279);
17444  return(false);
17445  }
17446  }
17447 
17448 // check for same route as start element
17450  {
17451  if(!Callon)
17452  {
17453  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
17454  }
17455  Utilities->CallLogPop(280);
17456  return(false);
17457  }
17458 // check for a looping route
17459  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
17460  {
17462  {
17463  if(!Callon)
17464  {
17465  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
17466  }
17467  Utilities->CallLogPop(1845);
17468  return(false);
17469  }
17470  }
17471 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
17472 // so search from this element.
17473 
17474  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
17475 
17476  if(StartSelectionRouteID > -1)
17477  {
17478  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
17479  {
17481  if(PointsToBeChanged(0, NewFailedPointsTVPos))
17482  {
17483  if(NewFailedPointsTVPos > -1)
17484  {
17485  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
17486  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
17487  " failed during route setting.");
17488  Utilities->CallLogPop(2504);
17489  return(false);
17490  }
17491  PointsChanged = true;
17492  }
17493  Utilities->CallLogPop(281);
17494  return(true);
17495  }
17496  else
17497  {
17498  if(!Callon && !Track->SuppressRouteFailMessage)
17499  {
17501  }
17502  Utilities->CallLogPop(282);
17503  return(false);
17504  }
17505  }
17506  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
17507  // search on the 2 ways out of the element, which has to be a 2-ended element
17508  {
17509 // check if selection adjacent to start element and if so use that
17510  if(SearchVector.at(0).Conn[0] == EndPosition)
17511  {
17512  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
17513  {
17515  if(PointsToBeChanged(1, NewFailedPointsTVPos))
17516  {
17517  if(NewFailedPointsTVPos > -1)
17518  {
17519  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
17520  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
17521  " failed during route setting.");
17522  Utilities->CallLogPop(2506);
17523  return(false);
17524  }
17525  PointsChanged = true;
17526  }
17527  Utilities->CallLogPop(283);
17528  return(true);
17529  }
17530  else
17531  {
17532  if(!Callon && !Track->SuppressRouteFailMessage)
17533  {
17535  }
17536  Utilities->CallLogPop(284);
17537  return(false);
17538  }
17539  }
17540  else if(SearchVector.at(0).Conn[1] == EndPosition)
17541  {
17542  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
17543  {
17545  if(PointsToBeChanged(2, NewFailedPointsTVPos))
17546  {
17547  if(NewFailedPointsTVPos > -1)
17548  {
17549  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
17550  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
17551  " failed during route setting.");
17552  Utilities->CallLogPop(2508);
17553  return(false);
17554  }
17555  PointsChanged = true;
17556  }
17557  Utilities->CallLogPop(285);
17558  return(true);
17559  }
17560  else
17561  {
17562  if(!Callon && !Track->SuppressRouteFailMessage)
17563  {
17565  }
17566  Utilities->CallLogPop(286);
17567  return(false);
17568  }
17569  }
17570  // now start off in the best direction
17571  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
17572 
17573  if(SearchVector.at(0).Config[BestPos] != End)
17574  {
17575  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17576  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
17577  {
17579  if(PointsToBeChanged(3, NewFailedPointsTVPos))
17580  {
17581  if(NewFailedPointsTVPos > -1)
17582  {
17583  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
17584  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
17585  " failed during route setting.");
17586  Utilities->CallLogPop(2510);
17587  return(false);
17588  }
17589  PointsChanged = true;
17590  }
17591  Utilities->CallLogPop(287);
17592  return(true);
17593  }
17594  }
17595  if(SearchVector.at(0).Config[1 - BestPos] != End)
17596  {
17597  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17598  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
17599  {
17601  if(PointsToBeChanged(4, NewFailedPointsTVPos))
17602  {
17603  if(NewFailedPointsTVPos > -1)
17604  {
17605  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
17606  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
17607  " failed during route setting.");
17608  Utilities->CallLogPop(2512);
17609  return(false);
17610  }
17611  PointsChanged = true;
17612  }
17613  Utilities->CallLogPop(288);
17614  return(true);
17615  }
17616  }
17617  }
17618  if(!Callon && !Track->SuppressRouteFailMessage)
17619  {
17621  }
17622  Utilities->CallLogPop(289);
17623  return(false);
17624 }
17625 
17626 // ---------------------------------------------------------------------------
17627 
17628 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
17629 /*
17630  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
17631  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
17632  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
17633  Keep a count of entries in SearchVector during the current function call, so that this number can be
17634  erased for an unproductive branch search.
17635  First check (within the loop) whether XLink leads to an End & return false if so.
17636  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
17637  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
17638  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
17639  train on element (unless a bridge & train on different track), or if element
17640  fouls an existing diagonal route (except if element is a leading point - these checked later).
17641  Then check if found required element. If so save it & return true.
17642  If not the required element check if buffer or continuation, & if so erase all searchvector
17643  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
17644  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
17645  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
17646  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
17647  When return true have 8 items from CheckCount established, only waiting for EXNumber
17648 */
17649 {
17650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
17651  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
17652  int VectorCount = 0;
17653 
17654 // check for a fouled diagonal for first element. Added for v1.3.2
17655  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
17656  (CurrentTrackElement.Link[XLinkPos] == 9))
17657  {
17658  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
17659  {
17660  for(int x = 0; x < VectorCount; x++)
17661  {
17662  SearchVector.erase(SearchVector.end() - 1);
17663  }
17664  Utilities->CallLogPop(2044);
17665  return(false);
17666  }
17667  }
17668  while(true)
17669  {
17670  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
17671  {
17672  for(int x = 0; x < VectorCount; x++)
17673  {
17674  SearchVector.erase(SearchVector.end() - 1);
17675  }
17676  Utilities->CallLogPop(1927);
17677  return(false);
17678  }
17679  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
17680  {
17681  for(int x = 0; x < VectorCount; x++)
17682  {
17683  SearchVector.erase(SearchVector.end() - 1);
17684  }
17685  Utilities->CallLogPop(290);
17686  return(false);
17687  }
17688  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
17689  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
17690  TPrefDirElement SearchElement(NextTrackElement);
17691  SearchElement.TrackVectorPosition = NextPosition;
17692  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
17693  SearchElement.ELinkPos = NextELinkPos;
17694  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
17695  int NextXLinkPos;
17696  if(SearchElement.ELinkPos == 0)
17697  {
17698  NextXLinkPos = 1;
17699  }
17700  if(SearchElement.ELinkPos == 1)
17701  {
17702  NextXLinkPos = 0;
17703  }
17704  if(SearchElement.ELinkPos == 2)
17705  {
17706  NextXLinkPos = 3;
17707  }
17708  if(SearchElement.ELinkPos == 3)
17709  {
17710  NextXLinkPos = 2;
17711  }
17712  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
17713  {
17714  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
17715  // but may be buffers, continuation or gap
17716  SearchElement.XLinkPos = NextXLinkPos;
17717  }
17718 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
17719 // can't set XLink or XLinkPos yet if the element is a leading point.
17720 
17721 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
17722  drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of crossovers as can reach
17723  element on opposite track and still find the required end point - causes error when adding to the Route"MultiMap (happened by chance when
17724  developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search through all searchvector.
17725 
17726  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
17727 */
17728  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
17729  {
17730  for(unsigned int x = 0; x < SearchVector.size(); x++)
17731  {
17732  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
17733  {
17734  for(int x = 0; x < VectorCount; x++)
17735  {
17736  SearchVector.erase(SearchVector.end() - 1);
17737  }
17738  Utilities->CallLogPop(2655);
17739  return(false);
17740  }
17741  }
17742  }
17743  else if(SearchElement.TrackType == Bridge)
17744  {
17745  for(unsigned int x = 0; x < SearchVector.size(); x++)
17746  {
17747  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
17748  (SearchElement.ELink == SearchVector.at(x).ELink))
17749  {
17750  for(int x = 0; x < VectorCount; x++)
17751  {
17752  SearchVector.erase(SearchVector.end() - 1);
17753  }
17754  Utilities->CallLogPop(2656);
17755  return(false);
17756  }
17757  }
17758  }
17759 
17760 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
17761  TAllRoutes::TRouteElementPair SecondPair;
17763  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
17764  if(RoutePair.first > -1)
17765  {
17766  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
17767  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
17768  RoutePair.second).ELinkPos)))
17769  {
17770  // still OK if start of an expected route
17771  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
17772  {
17773  for(int x = 0; x < VectorCount; x++)
17774  {
17775  SearchVector.erase(SearchVector.end() - 1);
17776  }
17777  Utilities->CallLogPop(292);
17778  return(false); // only allow for start of an expected route
17779  }
17780  }
17781  }
17782  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
17783  {
17784  // OK if it's a bridge & routes on different tracks
17785  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
17786  SecondPair.second).ELinkPos)))
17787  {
17788  // still OK if start of an expected route
17789  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
17790  {
17791  for(int x = 0; x < VectorCount; x++)
17792  {
17793  SearchVector.erase(SearchVector.end() - 1);
17794  }
17795  Utilities->CallLogPop(293);
17796  return(false); // only allow for start of an expected route
17797  }
17798  }
17799  }
17800 // check if a train on element, unless a bridge & train on different track
17801 // OK of same train as start element - no, drop this
17802 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
17803  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
17804  {
17805  for(int x = 0; x < VectorCount; x++)
17806  {
17807  SearchVector.erase(SearchVector.end() - 1);
17808  }
17809  Utilities->CallLogPop(294);
17810  return(false);
17811  }
17812  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
17813  {
17814  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
17815  {
17816  for(int x = 0; x < VectorCount; x++)
17817  {
17818  SearchVector.erase(SearchVector.end() - 1);
17819  }
17820  Utilities->CallLogPop(295);
17821  return(false);
17822  }
17823  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
17824  {
17825  for(int x = 0; x < VectorCount; x++)
17826  {
17827  SearchVector.erase(SearchVector.end() - 1);
17828  }
17829  Utilities->CallLogPop(296);
17830  return(false);
17831  }
17832  }
17833 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
17834  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17835  {
17836  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17837  {
17838  for(int x = 0; x < VectorCount; x++)
17839  {
17840  SearchVector.erase(SearchVector.end() - 1);
17841  }
17842  Utilities->CallLogPop(297);
17843  return(false);
17844  }
17845  }
17846 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
17847 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
17848 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
17850  {
17851  for(int x = 0; x < VectorCount; x++)
17852  {
17853  SearchVector.erase(SearchVector.end() - 1);
17854  }
17855  Utilities->CallLogPop(1689);
17856  return(false);
17857  }
17858 // check if found it
17859  if(SearchElement.TrackVectorPosition == RequiredPosition)
17860  {
17861  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
17862  {
17863  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
17864  {
17865  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
17866  }
17867  else
17868  {
17869  SearchElement.XLinkPos = 1;
17870  }
17871 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
17872  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
17873  }
17874  SearchVector.push_back(SearchElement);
17875  VectorCount++; // not really needed but include for tidyness
17876  TotalSearchCount++;
17877  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
17878  {
17879  for(int x = 0; x < VectorCount; x++)
17880  {
17881  SearchVector.erase(SearchVector.end() - 1);
17882  }
17883  Utilities->CallLogPop(2525);
17884  return(false);
17885  }
17886  Utilities->CallLogPop(298);
17887  return(true);
17888  }
17889 // Not the required element - check if a buffer or continuation
17890  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
17891  {
17892  for(int x = 0; x < VectorCount; x++)
17893  {
17894  SearchVector.erase(SearchVector.end() - 1);
17895  }
17896  Utilities->CallLogPop(299);
17897  return(false);
17898  }
17899 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
17901  {
17902  for(int x = 0; x < VectorCount; x++)
17903  {
17904  SearchVector.erase(SearchVector.end() - 1);
17905  }
17906  Utilities->CallLogPop(1421);
17907  return(false);
17908  }
17909 //deal with failed points, added at v2.13.0
17910  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
17911  {
17912  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
17913  {
17914  SearchElement.XLinkPos = 1;
17915  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17916  }
17917  else
17918  {
17919  SearchElement.XLinkPos = 3;
17920  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17921  }
17922  }
17923  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
17924  {
17925  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
17926  {
17927  for(int x = 0; x < VectorCount; x++)
17928  {
17929  SearchVector.erase(SearchVector.end() - 1);
17930  }
17931  Utilities->CallLogPop(2533);
17932  return(false);
17933  }
17934  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
17935  {
17936  for(int x = 0; x < VectorCount; x++)
17937  {
17938  SearchVector.erase(SearchVector.end() - 1);
17939  }
17940  Utilities->CallLogPop(2534);
17941  return(false);
17942  }
17943  }
17944 
17945 // check if reached a non-failed leading point
17946  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
17947  { //added !Failed condition at v2.13.0 to exclude failed points
17948 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17949  int SearchPos1 = SearchElement.Attribute + 1;
17950  int SearchPos2;
17951  if(SearchPos1 == 2)
17952  {
17953  SearchPos1++;
17954  }
17955  if(SearchPos1 == 1)
17956  {
17957  SearchPos2 = 3;
17958  }
17959  else
17960  {
17961  SearchPos2 = 1;
17962  }
17963 // push element with XLink set to position [SearchPos1]
17964  SearchElement.XLink = SearchElement.Link[SearchPos1];
17965  SearchElement.XLinkPos = SearchPos1;
17966 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17967  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17968  {
17969  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17970  {
17971  for(int x = 0; x < VectorCount; x++)
17972  {
17973  SearchVector.erase(SearchVector.end() - 1);
17974  }
17975  Utilities->CallLogPop(300);
17976  return(false);
17977  }
17978  }
17979  SearchVector.push_back(SearchElement);
17980  VectorCount++;
17981  TotalSearchCount++;
17982 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17983 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17984 // recursive search as has to be a TTrackElement for non-preferred route searches
17985  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17986  {
17987  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17988  {
17989  for(int x = 0; x < VectorCount; x++)
17990  {
17991  SearchVector.erase(SearchVector.end() - 1);
17992  }
17993  Utilities->CallLogPop(2526);
17994  return(false);
17995  }
17996  Utilities->CallLogPop(301);
17997  return(true);
17998  }
17999  else
18000  {
18001 // remove leading point with XLinkPos [SearchPos1]
18002  SearchVector.erase(SearchVector.end() - 1);
18003  VectorCount--;
18004 // push element with XLink set to position [SearchPos2]
18005  SearchElement.XLink = SearchElement.Link[SearchPos2];
18006  SearchElement.XLinkPos = SearchPos2;
18007 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
18008  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
18009  {
18010  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
18011  {
18012  for(int x = 0; x < VectorCount; x++)
18013  {
18014  SearchVector.erase(SearchVector.end() - 1);
18015  }
18016  Utilities->CallLogPop(302);
18017  return(false);
18018  }
18019  }
18020  SearchVector.push_back(SearchElement);
18021  VectorCount++;
18022  TotalSearchCount++;
18023 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
18024  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
18025  {
18026  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
18027  {
18028  for(int x = 0; x < VectorCount; x++)
18029  {
18030  SearchVector.erase(SearchVector.end() - 1);
18031  }
18032  Utilities->CallLogPop(2527);
18033  return(false);
18034  }
18035  Utilities->CallLogPop(303);
18036  return(true);
18037  }
18038  else
18039  {
18040  for(int x = 0; x < VectorCount; x++)
18041  {
18042  SearchVector.erase(SearchVector.end() - 1);
18043  }
18044  Utilities->CallLogPop(304);
18045  return(false);
18046  }
18047  }
18048  } // if leading point
18049 
18050 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
18051 // ready for next element on route
18052  SearchVector.push_back(SearchElement);
18053  VectorCount++;
18054  TotalSearchCount++;
18055  CurrentTrackElement = SearchElement;
18056  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
18057  } // while(true)
18058 }
18059 
18060 // ---------------------------------------------------------------------------
18061 
18063 
18064 /*
18065  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
18066  having all values set (since not necessarily on PrefDirs).
18067  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
18068  (if it was the start), so these are checked first and set if necessary. All elements now have
18069  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
18070  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
18071  to set the route colour and direction graphics.
18072 */
18073 
18074 {
18075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
18076  if(SearchVector.size() == 0)
18077  {
18078  throw Exception("Error, SearchVector empty");
18079  }
18080 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
18081 // hence need to examine and update it if necessary
18082  TPrefDirElement SecondElement;
18083 
18084  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
18085  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
18086  // need above check or SecondElement will fail
18087  {
18088  SecondElement = SearchVector.at(1);
18089  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
18090  for(int x = 0; x < 4; x++)
18091  {
18092  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
18093  {
18094  if(SearchVector.at(0).XLink == -1) // i.e. not set
18095  {
18096  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
18097  SearchVector.at(0).XLinkPos = x;
18098  }
18099  int ELinkPos;
18100  if(SearchVector.at(0).XLinkPos == 0)
18101  {
18102  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
18103  }
18104  // linked to 1st searchvector element, & if XLink was set then x may not correspond
18105  if(SearchVector.at(0).XLinkPos == 1)
18106  {
18107  ELinkPos = 0;
18108  }
18109  if(SearchVector.at(0).XLinkPos == 2)
18110  {
18111  ELinkPos = 3;
18112  }
18113  if(SearchVector.at(0).XLinkPos == 3)
18114  {
18115  ELinkPos = 2;
18116  }
18117  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
18118  {
18119  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
18120  SearchVector.at(0).ELinkPos = ELinkPos;
18121  }
18122  break; // no point going any further
18123  }
18124  }
18125  }
18126  for(unsigned int x = 0; x < SearchVector.size(); x++)
18127  {
18128  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
18129 // set EXNumber
18130  if(!(SearchVector.at(x).EntryExitNumber()))
18131  {
18132  throw Exception("Error in EntryExitNumber 3");
18133  }
18134  SearchVector.at(x).CheckCount++;
18135 // all values now incorporated
18136  }
18137 
18138  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
18139 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
18140 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
18141  Utilities->CallLogPop(305);
18142 }
18143 
18144 // ---------------------------------------------------------------------------
18145 
18147 
18148 /*
18149  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
18150  AutoSigsRoute.
18151  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
18152  beginning or the end.
18153  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
18154  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
18155  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
18156  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
18157  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
18158  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
18159  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
18160 
18161  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
18162  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
18163  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
18164  route at the start.
18165 
18166  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
18167  for the new route and return.
18168 */
18169 
18170 {
18171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
18172  AnsiString(ReqPosRouteID.GetInt()));
18173  if(SearchVector.size() < 1)
18174  {
18175  Utilities->CallLogPop(306);
18176  return;
18177  }
18178  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
18179  if(!ValidatePrefDir(6))
18180  {
18181  Utilities->CallLogPop(307);
18182  return;
18183  }
18184  TAllRoutes::TLockedRouteClass LockedRouteObject;
18185 
18187  unsigned int TruncatePrefDirPosition = 0;
18188 
18189  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
18190 /* if have ReqPosRouteID:
18191  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
18192  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
18193  then enter the new route into the AllRoutesVector
18194 */
18195  {
18197  {
18198  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
18199  x++) // start at 1 as first element already in SearchVector
18200  {
18202  }
18203  // note that route numbers in map adjusted when ReqPos route cleared
18205  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
18206  // set during ClearRouteDuringRouteBuildingAt)
18208  {
18211  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
18212  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
18213  }
18214  }
18216  {
18217  SearchVector.pop_back();
18218  }
18219  }
18220  if(StartSelectionRouteID > -1)
18221 /* if have StartSelectionRouteID:
18222  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
18223  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
18224 */
18225  {
18227  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
18228  {
18230  {
18231  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
18232  for(unsigned int x = 0; x < SearchVector.size(); x++)
18233  {
18235  RouteNumber, GetFixedSearchElementAt(7, x));
18236  // find & store locked route truncate position in PrefDirVector for later use
18238  {
18239  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
18240  {
18241  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
18242  }
18243  }
18244  }
18246  {
18247  throw Exception("Failed to validate extended route for nonpreferred route");
18248  }
18251  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
18252  // now add the reinstated locked route if required and set signals accordingly
18253  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
18254  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
18255  // that I haven't thought of
18257  {
18258  LockedRouteObject.RouteNumber = RouteNumber;
18259  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
18260  // now reset the signals for the locked route
18261  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
18262  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
18263  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
18264  {
18265  // return all signals to red in route section to be truncated
18266  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
18267  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
18268  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18269  {
18270  TrackElement.Attribute = 0;
18271  Track->PlotSignal(11, TrackElement, Display);
18272  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18273  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18274  }
18275  }
18276  }
18277  AllRoutes->CheckMapAndRoutes(3); // test
18278  Utilities->CallLogPop(308);
18279  return;
18280  }
18281  }
18282  else
18283  {
18285  }
18286 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
18287 // hence nothing to do here
18288  }
18289  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
18290  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
18291  {
18292  throw Exception("Failed to validate single route for nonpreferred route");
18293  }
18294  AllRoutes->StoreOneRoute(2, this);
18295  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
18296  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
18297  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
18298  AllRoutes->CheckMapAndRoutes(4); // test
18299  Utilities->CallLogPop(309);
18300 }
18301 
18302 // ---------------------------------------------------------------------------
18303 
18304 void TOneRoute::SetRoutePoints(int Caller) const
18305 /*
18306  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
18307  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
18308  when they were created.
18309 */
18310 {
18311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
18312  if(!PrefDirVector.empty())
18313  {
18314  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18315  {
18316  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
18317  {
18318  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
18319  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
18320  }
18321  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
18322  {
18323  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
18324  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
18325  }
18326  }
18327  }
18328  Utilities->CallLogPop(327);
18329 }
18330 
18331 // ---------------------------------------------------------------------------
18332 
18333 void TOneRoute::SetRouteSignals(int Caller) const
18334 // Used for new train additions in AddTrain and in route setting, major changes at v2.17.0
18335 
18336 {
18337  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
18338  if(!PrefDirVector.empty())
18339  {
18340  int RouteNumber;
18341  int Attribute = 0;
18342  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
18343  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
18344  if(RouteType != TAllRoutes::NoRoute)
18345  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
18346  {
18347  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
18348  }
18349  }
18350  Utilities->CallLogPop(1720);
18351 }
18352 
18353 // ---------------------------------------------------------------------------
18354 
18355 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
18356 {
18357  //true if at any point in SearchVector points have to be changed,
18358  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
18359  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
18360  NewFailedPointsTVPos = -1; //default value for no new failure
18361  bool PointsChanged = false;
18362  if(!SearchVector.empty())
18363  {
18364  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
18365  {
18366  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
18367  //check for an existing failed point where needs to change to make the route
18368  int Attr = TE.Attribute;
18369  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
18370  {
18371  if(Attr == 1) //currently set to diverge
18372  {
18373  //here add new failure possibility at v2.13.0
18374  if(Utilities->FailureMode != FNil)
18375  {
18376  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18377  {
18379  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18380  IFE.TVPos = NewFailedPointsTVPos;
18381  TE.Failed = true;
18382  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18384  TE.SpeedLimit01 = 10; //values while failed
18385  TE.SpeedLimit23 = 10;
18386  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18387  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18388  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18389  //set repair time, random value in minutes between 10 and 179
18390  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18391  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18392  IFE.RepairTime = RepairTime;
18394  Track->FailedPointsVector.push_back(IFE);
18395  Utilities->CallLogPop(1717);
18396  return(true); //return so only allow one failure per route
18397  }
18398  }
18399  PointsChanged = true; //this is used for setting the flash time
18400  }
18401  }
18402  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
18403  {
18404  if(Attr == 0) //currently set to go straight
18405  {
18406  //here add failure possibility at v2.13.0
18407  if(Utilities->FailureMode != FNil)
18408  {
18409  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18410  {
18412  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18413  IFE.TVPos = NewFailedPointsTVPos;
18414  TE.Failed= true;
18415  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18417  TE.SpeedLimit01 = 10; //values while failed
18418  TE.SpeedLimit23 = 10;
18419  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18420  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18421  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18422  //set repair time, random value in minutes between 10 and 179
18423  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
18424  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18425  IFE.RepairTime = RepairTime;
18427  Track->FailedPointsVector.push_back(IFE);
18428  Utilities->CallLogPop(1718);
18429  return(true); //only allow one failure per route
18430  }
18431  }
18432  PointsChanged = true;
18433  }
18434  }
18435  }
18436  }
18437  Utilities->CallLogPop(1719);
18438  return(PointsChanged);
18439 }
18440 
18441 // ---------------------------------------------------------------------------
18442 
18443 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
18444 /* //added StartPos at v2.17.0 so it starts in the current route
18445 
18446  Only called by SetRearwardsSignalsReturnFalseForTrainInRear
18447 
18448  Works forward through the route from & including StartPos until finds:-
18449  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18450  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
18451  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
18452  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18453  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
18454  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18455  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18456  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18457  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
18458 */
18459 {
18460  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
18461  Attribute = 0;
18462  NextForwardLinkedRouteNumber = -1;
18463  for(unsigned int x = StartPos; x < PrefDirSize(); x++)
18464  {
18465  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
18466  if(PrefDirVector.at(x).TrackType == Bridge)
18467  {
18468  if(PrefDirVector.at(x).XLinkPos < 2)
18469  {
18470  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18471  }
18472  else
18473  {
18474  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18475  }
18476  }
18477  if(TrainID != -1)
18478  {
18479  Utilities->CallLogPop(328); //attribute still 0
18480  return(true);
18481  }
18482  if(PrefDirVector.at(x).TrackType == Buffers)
18483  {
18484  Attribute = 1;
18485  Utilities->CallLogPop(329);
18486  return(true);
18487  }
18488  if(PrefDirVector.at(x).TrackType == Continuation)
18489  {
18490  Attribute = 3;
18491  Utilities->CallLogPop(330);
18492  return(true);
18493  }
18494  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18495  {
18496  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18497  {
18498  Attribute = 0;
18499  Utilities->CallLogPop(1950);
18500  return(true);
18501  }
18502  }
18503  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
18504  {
18505  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
18506  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
18507  {
18508  Attribute++;
18509  }
18510  if(Attribute > 3)
18511  {
18512  Attribute = 3;
18513  }
18514  Utilities->CallLogPop(331);
18515  return(true);
18516  }
18517  if(x == PrefDirSize() - 1) //end element and not signal, buffer, continuation or LC, and no train on element
18518  {
18519  TPrefDirElement LastElement = GetFixedPrefDirElementAt(268, x);
18520  NextForwardLinkedRouteNumber = -1;
18521  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(42, Track->TrackElementAt(1579, LastElement.TrackVectorPosition).Conn[LastElement.XLinkPos], Track->TrackElementAt(1580, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos], NextForwardLinkedRouteNumber);
18522 //the above returns a route (or no route) but LinkPos can be entry or exit, so still need to know it's the entry link for the follow-on route to be valid
18523  if(!(RouteType == TAllRoutes::NoRoute)) //probably a forward route but still need to check if it's linked
18524  {
18525  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(227, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(269, 0); //0 is start position
18526  if(NewRoutePDE.ELinkPos == Track->TrackElementAt(1581, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos]) //if it's not then route not linked so there's no forward route
18527  {
18528  Attribute = 0;
18529  Utilities->CallLogPop(332);
18530  return(false);
18531  }
18532  //else there is no forward route, so return true with attribute still 0
18533  }
18534  //else there is no forward route, so return true with attribute still 0
18535  }
18536  }
18537  Utilities->CallLogPop(333); //
18538  return(true);
18539 }
18540 
18541 // ---------------------------------------------------------------------------
18542 
18543 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
18544 /* Major changes at v2.17.0
18545  This function is only called by TAllRoutes::SetAllRearwardsSignals.
18546 
18547  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18548  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18549  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
18550  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
18551  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
18552  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
18553  or (c) truncating a route.
18554 
18555  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18556  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
18557  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
18558  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
18559  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
18560  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
18561  the function returns true.
18562 
18563  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
18564  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18565 */
18566 {
18567  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrainInRear," + AnsiString(Attribute) + "," +
18568  AnsiString(PrefDirVectorStartPosition));
18569  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
18570  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
18571 // if no train or closed LC between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
18572 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
18573 
18574  if(!PrefDirVector.empty())
18575  {
18576  if(!SkipForwardLook)
18577  {
18578  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
18579  {
18580  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18581  if(PrefDirPtr->TrackType == Bridge)
18582  {
18583  if(PrefDirPtr->XLinkPos < 2)
18584  {
18585  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18586  }
18587  else
18588  {
18589  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18590  }
18591  }
18592  if(TrainID != -1)
18593  {
18594  SkipForwardLook = true;
18595  break;
18596  }
18597  }
18598  }
18599 
18601  {
18602  SkipForwardLook = true;
18603  }
18604 
18605  int NextForwardLinkedRouteNumber = -1;
18606  if((unsigned int)PrefDirVectorStartPosition == PrefDirSize() - 1) //end element of route
18607  {
18608  TPrefDirElement PDE = GetFixedPrefDirElementAt(267, PrefDirVectorStartPosition);
18610 //the above returns a route (or no route) but LinkPos can be entry or exit, and need to know it's the entry link for the follow-on route to be valid
18611  if(RouteType == TAllRoutes::NoRoute)
18612  {
18613  SkipForwardLook = true; //if there's no linked forward route then skip
18614  if(PrefDirVector.back().TrackType == Buffers)
18615  {
18616  Attribute = 1; // treat buffer as red signal
18617  }
18618  if(PrefDirVector.back().TrackType == Continuation)
18619  { //check if timing out and no train between 1st signal and continuation and if so don't change attribute
18620  bool SetAttributeTo3 = true;
18623  {
18624  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
18625  AutoSigVectorIT++)
18626  {
18627  if(!AllRoutes->AllRoutesVector.empty())
18628  {
18629  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
18630  {
18631  SetAttributeTo3 = false;
18632  Attribute = AutoSigVectorIT->AccessNumber;
18633  break;
18634  }
18635  }
18636  }
18637  }
18638  if(SetAttributeTo3)
18639  {
18640  Attribute = 3; // treat continuation as a green signal
18641  }
18642  }
18643  }
18644  else //startpos still on end element and there is probably a forward route
18645  {
18646  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(228, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(270, 0); //0 is start position
18647  if(NewRoutePDE.ELinkPos != Track->TrackElementAt(1584, PDE.TrackVectorPosition).ConnLinkPos[PDE.XLinkPos]) //if it's not then route not linked so there's no forward route
18648  {
18649  SkipForwardLook = true; //if there's no linked forward route then skip
18650  if(PrefDirVector.back().TrackType == Buffers)
18651  {
18652  Attribute = 1; // treat buffer as red signal
18653  }
18654  if(PrefDirVector.back().TrackType == Continuation)
18655  {
18656  Attribute = 3; // treat continuation as a green signal
18657  }
18658  }
18659  //else there is a forward route, so just continue to examine it below unless SkipForwardLook is true
18660  }
18661  }
18662 
18663  if(!SkipForwardLook)
18664  {
18665  //start from element in front of PrefDirVectorStartPosition, which may be in same or next forward route (if there isn't one then
18666  //SkipForwardLook will be true - see above)
18667  int StartPos;
18668  if((unsigned int)PrefDirVectorStartPosition < (PrefDirSize() - 1))
18669  {
18670  StartPos = PrefDirVectorStartPosition + 1;
18671  }
18672  else
18673  {
18674  StartPos = 0; //start of next forward route
18675  }
18676  if(StartPos > 0) //starting in this route
18677  {
18678  if(!FindForwardTargetSignalAttribute(2, NextForwardLinkedRouteNumber, Attribute, StartPos))// returns false for having to link to next route to continue search
18679  {
18680  StartPos = 0; //reset to 0 for next route
18681  while(!AllRoutes->GetFixedRouteAt(229, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(3, NextForwardLinkedRouteNumber, Attribute, StartPos))
18682  {
18683  continue;
18684  }
18685  }
18686  }
18687  else //starting in next forward route
18688  {
18689  while(!AllRoutes->GetFixedRouteAt(230, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(4, NextForwardLinkedRouteNumber, Attribute, StartPos))
18690  {
18691  continue;
18692  }
18693  }
18694  }
18695 
18696  //now have target attribute (as supplied or modified in forward look) so look backwards to set signals
18697  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18698  {
18699  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18700  if(PrefDirPtr->TrackType == Bridge)
18701  {
18702  if(PrefDirPtr->XLinkPos < 2)
18703  {
18704  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18705  }
18706  else
18707  {
18708  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18709  }
18710  }
18711  if(TrainID != -1)
18712  {
18713  Utilities->CallLogPop(334);
18714  return(false);
18715  }
18716  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
18717  // the attribute to 0 so first signal behind the LC is red
18718  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18719  {
18720  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18721  {
18722  Attribute = 0;
18723  }
18724  }
18725 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
18726 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18727  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
18728  {
18729  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
18730  PrefDirPtr->PrefDirRoute)
18731  {
18732 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
18733 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
18734  int LockedVecNum = 0; //not used
18735  TPrefDirElement DummyPrefDir; //not used
18736  bool KeepAttributeAt0ForLockedRoute = false;
18737  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
18738  LockedVecNum))
18739  {
18740  Attribute = 0;
18741  KeepAttributeAt0ForLockedRoute = true;
18742  }
18743 //end of v2.9.2 addition
18744 
18745 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
18746  bool NotGroundSignal = false;
18747  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
18748  {
18749  NotGroundSignal = true;
18750  }
18751 
18752  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
18753  {
18754  Attribute = 0; //stays at 0
18755  }
18756 
18757  if(Attribute < 3)
18758  {
18759  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
18760  }
18761  else
18762  {
18763  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
18764  }
18765  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
18766  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
18767  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
18768  {
18769  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18770  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
18771  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18772  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
18773  }
18774  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
18775  { //if groundsignal attrib is 0 then do need to increment
18776  Attribute++; //this is for the next signal rearwards, not the current one
18777  }
18778 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
18779  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
18780  }
18781  }
18782  }
18783  }
18784  Utilities->CallLogPop(335);
18785  return(true);
18786 }
18787 
18788 // ---------------------------------------------------------------------------
18789 
18790 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
18791 /*
18792  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
18793  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
18794  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
18795  Selection invalid if select a bridge; trying to leave a single element; last element to be left
18796  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
18797  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
18798  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
18799  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
18800 
18801  Note that this function was heavily modified at v2.21.0 when clicking a signal truncates to next signal - with additional conditions, see click table below
18802 */
18803 {
18804  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18805  "," + AnsiString((short)PrefDirRoute));
18806  bool ElementInRoute = false;
18807  TOneRoute ReinstatementRoute = *this; //added at v2.21.0 for truncation to next signal
18808  int LastElementToBeTruncated = -1; //added at v2.21.0 for truncation to next signal
18809  bool MovingTrainOccupyingRoute = false;
18810  unsigned int TruncatePDElementPos; //the selected PD position to truncate to & include in the truncation (could be from the back or the front)//added at v2.15.0
18811  enum {NoTruncate, BackTruncate, FrontTruncate, NextSignalTruncate, FullTruncate} TruncateType;
18812  TruncateType = NoTruncate;
18813  AllRoutes->RouteTruncateFlag = false;
18814  //first check the truncate point is in a route
18815  for(unsigned int b = 0; b < PrefDirSize(); b++)
18816  {
18817  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
18818  {
18819  TruncatePDElementPos = b;
18820  ElementInRoute = true;
18821  break;
18822  }
18823  }
18824  if(!ElementInRoute)
18825  {
18826  ReturnFlag = NotInRoute;
18827  Utilities->CallLogPop(336);
18828  return;
18829  }
18830 
18831  //click table
18832  //click route sig position result
18833 
18834  //element after signal any mid-route BackTruncate
18835  //element after signal any start of route Not allowed (message given saying would leave single element)
18836  //element before signal any mid-route FrontTruncate
18837  //element before signal any end of route Not allowed (message given saying would leave single element)
18838  //signal any mid-route & signal after that isn't the end NextSignalTruncate
18839  //signal any mid-route & signal after that is the end BackTruncate
18840  //signal any mid-route & no signal after BackTruncate
18841  //signal green or blue end of route Invalid element message
18842  //signal red end of route Erases last element only
18843  //start of route (signal or not)any n/a FullTruncate (never need to clear from entry to next signal as can add a signal)
18844  //end of route (not signal) green or blue n/a Give invalid element message
18845  //end of route (any element) red n/a Erases last element only
18846 
18847  //now find whether back, front, nextsignal (added at v2.21.0) or full truncate //added at v2.15.0, backtrucate = from truncate position to the end of the route (i.e. the original truncate function)
18848  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate as that requires a signal after the truncate point
18849  {
18850  if(TruncatePDElementPos == 0) //start of route
18851  {
18852  TruncateType = FullTruncate;
18853  AllRoutes->RouteTruncateFlag = true; //Added at v2.15.1: Set for all route truncate types, used in SetAllRearwardsSignals to prevent a forward look.
18854  //Without this, if a non-autosigs route is in front of an autosigs route and runs into buffers or a
18855  //continuation, and the non-autosigs route is truncated back to the autosigs route (i.e. a full
18856  //truncate for that route), the last signal in the autosigs route doesn't change to red.
18857  }
18858  else
18859  {
18860  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
18861  if(TempElement.Config[TempElement.XLinkPos] == Signal)
18862  {
18863  TruncateType = FrontTruncate;
18864  AllRoutes->RouteTruncateFlag = true; //to set signals properly rearwards of truncate point //added after v2.23.0 because of Fly California/Silicon Airways
18865  } //bug report via discord (ticket #87) where front truncated segment of a green route following a blue route & blue route end signal stayed green
18866  else //here could be back or next signal truncate, next sig truncate if truncate pos is a signal and there's a signal after that isn't the end of the route
18867  {
18868  TempElement = PrefDirVector.at(TruncatePDElementPos);
18869  if(TempElement.Config[TempElement.XLinkPos] == Signal) //possibly next sig truncate
18870  {
18871  TruncatePDElementPos++; //need to add one as in all cases don't want to truncate the signal itself, also there esists a +1 because of the first condition
18872  //now look forwards to next signal, if it's the end or no signal then it's BackTruncate
18873  int b;
18874  for(b = int(TruncatePDElementPos); b < int(PrefDirSize()); b++)
18875  {
18876  TempElement = PrefDirVector.at(b);
18877  if((TempElement.Config[TempElement.XLinkPos] == Signal) && (b < int(PrefDirSize() - 1))) //if met then it's a mid-route signal
18878  {
18879  TruncateType = NextSignalTruncate;
18880  AllRoutes->RouteTruncateFlag = true; //to set signals properly rearwards of truncate point - relies on rearwards sig setting before re-instatement route sig setting
18881  break; //re-instatement route sig setting
18882  }
18883  }
18884  if(b == int(PrefDirSize())) //i.e. haven't found a mid-route signal
18885  {
18886  TruncateType = BackTruncate;
18887  AllRoutes->RouteTruncateFlag = true;
18888  }
18889  }
18890  else
18891  {
18892  TruncateType = BackTruncate;
18893  AllRoutes->RouteTruncateFlag = true;
18894  }
18895  }
18896  }
18897  }
18898  else // == PrefDirSize() - 1, i.e. end of route
18899  {
18900  TruncateType = BackTruncate;
18901  AllRoutes->RouteTruncateFlag = true;
18902  }
18903 
18904 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
18905 
18906  if(TruncateType == BackTruncate) //added at v2.15.0
18907  {
18908  for(int b = PrefDirSize() - 1; b >= 0; b--)
18909  {
18910  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18911  if(PrefDirVector.at(b).TrackType == Bridge)
18912  {
18913  if(PrefDirVector.at(b).XLinkPos < 2)
18914  {
18915  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18916  }
18917  else
18918  {
18919  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18920  }
18921  }
18922  if(TrainID != -1)
18923  {
18924  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
18925  {
18926  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
18927  }
18928  }
18929  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18930  {
18931  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
18932  ReturnFlag = InRouteFalse;
18933  AllRoutes->RouteTruncateFlag = false;
18934  Utilities->CallLogPop(1941);
18935  return;
18936  }
18937  if(b == int(TruncatePDElementPos))
18938  {
18939  break; // OK found truncate element & no flashing LC in front
18940  }
18941  }
18942  }
18943  else if(TruncateType == NextSignalTruncate) //added at v2.15.0
18944  {
18945  //first look forward from truncate point to the next facing signal, which must be mid-route or wouldn't reach here
18946  TPrefDirElement TempElement;
18947  LastElementToBeTruncated = -1;
18948  for(unsigned int b = TruncatePDElementPos; b < PrefDirSize(); b++)
18949  {
18950  TempElement = PrefDirVector.at(b);
18951  if(TempElement.Config[TempElement.XLinkPos] == Signal) //found it
18952  {
18953  LastElementToBeTruncated = int(b) - 1;
18954  break;
18955  }
18956  }
18957  for(int b = LastElementToBeTruncated; b >= 0; b--) //just look for train in section to be erased
18958  {
18959  int TrainID = Track->TrackElementAt(1683, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18960  if(PrefDirVector.at(b).TrackType == Bridge)
18961  {
18962  if(PrefDirVector.at(b).XLinkPos < 2)
18963  {
18964  TrainID = Track->TrackElementAt(1684, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18965  }
18966  else
18967  {
18968  TrainID = Track->TrackElementAt(1685, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18969  }
18970  }
18971  if(TrainID != -1)
18972  {
18973  if(!TrainController->TrainVectorAtIdent(72, TrainID).Stopped())
18974  {
18975  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
18976  }
18977  }
18978  if(Track->IsLCBarrierFlashingAtHV(6, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18979  {
18980  TrainController->StopTTClockMessage(178, "Can't cancel a route containing a level crossing that is changing state");
18981  ReturnFlag = InRouteFalse;
18982  AllRoutes->RouteTruncateFlag = false;
18983  Utilities->CallLogPop(2713);
18984  return;
18985  }
18986  if(b == int(TruncatePDElementPos))
18987  {
18988  break; // OK found truncate element & no flashing LC in front
18989  }
18990  }
18991  //create a new route from the signal forwards to re-instate later
18992  ReinstatementRoute = *this;
18993 // ReinstatementRoute.RouteID = AllRoutes->NextRouteID; //this is allocated when store the route later on
18994 // AllRoutes->NextRouteID++;
18995  ReinstatementRoute.StartRoutePosition = PrefDirVector.at(LastElementToBeTruncated + 1).TrackVectorPosition;
18996  ReinstatementRoute.StartElement1 = PrefDirVector.at(LastElementToBeTruncated + 1);
18997  ReinstatementRoute.StartElement2 = PrefDirVector.at(LastElementToBeTruncated + 1);
18998  ReinstatementRoute.PrefDirVector.erase(ReinstatementRoute.PrefDirVector.begin(), ReinstatementRoute.PrefDirVector.begin() + LastElementToBeTruncated + 1);
18999  ReturnFlag = InRouteTrue;
19000  }
19001  else if(TruncateType == FrontTruncate)//front truncate //added at v2.15.0
19002  {
19003  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
19004  {
19005  int TrainID = Track->TrackElementAt(1577, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19006  if(PrefDirVector.at(b).TrackType == Bridge)
19007  {
19008  if(PrefDirVector.at(b).XLinkPos < 2)
19009  {
19010  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19011  }
19012  else
19013  {
19014  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19015  }
19016  }
19017  if(TrainID != -1)
19018  {
19019  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
19020  {
19021  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19022  }
19023  }
19024  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19025  {
19026  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
19027  ReturnFlag = InRouteFalse;
19028  AllRoutes->RouteTruncateFlag = false;
19029  Utilities->CallLogPop(2571);
19030  return;
19031  }
19032  if(b == TruncatePDElementPos)
19033  {
19034  break; // OK found truncate element & no flashing LC behind
19035  }
19036  }
19037  }
19038  else //FullTruncate
19039  {
19040  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
19041  {
19042  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19043  if(PrefDirVector.at(b).TrackType == Bridge)
19044  {
19045  if(PrefDirVector.at(b).XLinkPos < 2)
19046  {
19047  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19048  }
19049  else
19050  {
19051  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19052  }
19053  }
19054  if(TrainID != -1)
19055  {
19056  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
19057  {
19058  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19059  }
19060  }
19061  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19062  {
19063  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
19064  ReturnFlag = InRouteFalse;
19065  AllRoutes->RouteTruncateFlag = false;
19066  Utilities->CallLogPop(2572);
19067  return;
19068  }
19069  }
19070  }
19071  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
19072  {
19073  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
19074  ReturnFlag = InRouteFalse;
19075  AllRoutes->RouteTruncateFlag = false;
19076  Utilities->CallLogPop(338);
19077  return;
19078  }
19079  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
19080  {
19081  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
19082  ReturnFlag = InRouteFalse;
19083  AllRoutes->RouteTruncateFlag = false;
19084  Utilities->CallLogPop(339);
19085  return;
19086  }
19087 
19088  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
19089  {
19090  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
19091  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
19092  {
19093  if(TempElement.Config[TempElement.XLinkPos] != Signal)
19094  {
19095  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19096  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19097  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19098  "or to remove the whole route select the first track element in the route");
19099  ReturnFlag = InRouteFalse;
19100  AllRoutes->RouteTruncateFlag = false;
19101  Utilities->CallLogPop(340);
19102  return;
19103  }
19104  }
19105  else //this isn't appropriate for front truncate
19106  {
19107  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
19108  {
19109  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
19110  ReturnFlag = InRouteFalse;
19111  AllRoutes->RouteTruncateFlag = false;
19112  Utilities->CallLogPop(341);
19113  return;
19114  }
19115  }
19116  }
19117 
19118  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
19119  {
19120  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
19121  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
19122  {
19123  if(TempElement.Config[TempElement.XLinkPos] != Signal)
19124  {
19125  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19126  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19127  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19128  "or to remove the whole route select the first track element in the route");
19129  ReturnFlag = InRouteFalse;
19130  AllRoutes->RouteTruncateFlag = false;
19131  Utilities->CallLogPop(2573);
19132  return;
19133  }
19134  }
19135 /*
19136  else //red route //not appropriate for front truncate because the position in advance of the truncation position is to be truncated, it won't be left
19137  { // deleted at v2.21.0
19138  if(TruncatePDElementPos > 0)
19139  {
19140  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
19141  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
19142  {
19143  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
19144  ReturnFlag = InRouteFalse;
19145  AllRoutes->RouteTruncateFlag = false;
19146  Utilities->CallLogPop(2574);
19147  return;
19148  }
19149  }
19150  }
19151 */
19152  }
19153 
19154  else if(TruncatePDElementPos == 0) //full truncate
19155  {
19156  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
19157  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
19158  {
19159  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
19160  {
19161  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19162  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19163  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19164  "or to remove the whole route select the first track element in the route");
19165  ReturnFlag = InRouteFalse;
19166  AllRoutes->RouteTruncateFlag = false;
19167  Utilities->CallLogPop(2575);
19168  return;
19169  }
19170  }
19171  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
19172  {
19173  if(TempElement.TrackType == Bridge)
19174  {
19175  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
19176  ReturnFlag = InRouteFalse;
19177  AllRoutes->RouteTruncateFlag = false;
19178  Utilities->CallLogPop(2576);
19179  return;
19180  }
19181  }
19182  }
19183 
19184  int ThisRouteNumber;
19186 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
19187 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
19188 
19189 // check if part of this route already locked & disallow if so
19190  if(!(AllRoutes->LockedRouteVector.empty()))
19191  {
19193  {
19194  if(LRVIT->RouteNumber == ThisRouteNumber)
19195  {
19196  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
19197  ReturnFlag = InRouteFalse;
19198  AllRoutes->RouteTruncateFlag = false;
19199  Utilities->CallLogPop(749);
19200  return;
19201  }
19202  }
19203  }
19204 
19205  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
19206  if((TruncateType == BackTruncate) || (TruncateType == NextSignalTruncate)) //is within 3 running signals on this or linked rearwards routes, NextSigTruncate added at v2.21.0
19207  {
19208  LookBackwardsFromHere = TruncatePDElementPos;
19209  }
19210 
19211 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
19212  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
19213  int FrontPosition;
19214 
19215  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
19216  // before v2.1.0 RouteLockingRequired only checked for trains approaching
19217  {
19218  if(TruncateType == NextSignalTruncate) //added at v2.21.0 - don't allow trucation as would likely need to lock route further forwards than next signal
19219  {
19220  TrainController->StopTTClockMessage(179, "Unable to truncate to next signal when route locking is required. To apply locking truncate from the element "
19221  "immediately after the signal, this will lock the remainder of the route ");
19222  ReturnFlag = InRouteFalse;
19223  AllRoutes->RouteTruncateFlag = false;
19224  Utilities->CallLogPop(2714);
19225  return;
19226  }
19227  else
19228  {
19231  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
19232  L"Warning!", MB_YESNO | MB_ICONWARNING);
19233  TrainController->BaseTime = TDateTime::CurrentDateTime();
19235  if(button == IDNO)
19236  {
19237  ReturnFlag = InRouteTrue; // still return true even though don't act on it
19238  AllRoutes->RouteTruncateFlag = false;
19239  Utilities->CallLogPop(342);
19240  return;
19241  }
19242  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
19243  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
19244  TAllRoutes::TLockedRouteClass LockedRoute;
19245  bool ExistingLockedRouteModified = false;
19246  LockedRoute.RouteNumber = ThisRouteNumber;
19247  if(TruncateType == BackTruncate)
19248  {
19249  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
19250  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
19251  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
19252  }
19253  else if(TruncateType == FrontTruncate)
19254  {
19255  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
19256  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
19257  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
19258  }
19259  else //FullTruncate
19260  {
19261  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
19262  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
19263  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
19264  }
19265 
19266  LockedRoute.LockStartTime = TrainController->TTClockTime;
19267  // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
19268  // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
19269  if(!AllRoutes->LockedRouteVector.empty())
19270  {
19271  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
19272  LRVIT++)
19273  {
19274  if(LRVIT->RouteNumber == ThisRouteNumber)
19275  {
19276  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
19277  LRVIT->LockStartTime = LockedRoute.LockStartTime;
19278  ExistingLockedRouteModified = true;
19279  }
19280  }
19281  }
19282  if(!ExistingLockedRouteModified)
19283  {
19284  AllRoutes->LockedRouteVector.push_back(LockedRoute);
19285  }
19286  if(TruncateType == BackTruncate)
19287  {
19288  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
19289  RearPosition = TruncatePDElementPos;
19290  FrontPosition = PrefDirSize() - 1;
19291  }
19292  else if(TruncateType == FrontTruncate)
19293  {
19294  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
19295  RearPosition = 0;
19296  FrontPosition = TruncatePDElementPos;
19297  }
19298  else //FullTruncate
19299  {
19300  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
19301  RearPosition = 0;
19302  FrontPosition = PrefDirSize() - 1;
19303  }
19304  // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
19305  for(int c = FrontPosition; c >= RearPosition; c--)
19306  {
19307  // return all signals to red in route section to be truncated
19308  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
19309  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
19310  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
19311  {
19312  TrackElement.Attribute = 0;
19313  Track->PlotSignal(2, TrackElement, Display);
19314  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
19315  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
19316  }
19317  }
19318  // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
19319  ReturnFlag = InRouteTrue;
19320  }
19321  }
19322  else //route locking not required
19323  {
19324  if((TruncateType == BackTruncate) || (TruncateType == NextSignalTruncate)) //need to erase the whole route to the end, the new bit will be re-instated later
19325  { //for NextSignalTruncate
19326  RearPosition = TruncatePDElementPos;
19327  FrontPosition = PrefDirSize() - 1;
19328  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
19329  }
19330  else if(TruncateType == FrontTruncate)
19331  {
19332  RearPosition = 0;
19333  FrontPosition = TruncatePDElementPos;
19334  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
19335  }
19336  else //FullTruncate
19337  {
19338  RearPosition = 0;
19339  FrontPosition = PrefDirSize() - 1;
19340  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
19341  }
19342 
19343  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
19344  //into adjacent red or green routes if there are any (after the truncation/removal)
19345 
19346  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19347  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
19348 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
19349 
19350  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
19351  {
19352  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
19353  ReturnFlag = InRouteTrue;
19354  }
19355 
19356  if(TruncateType == NextSignalTruncate) //re-instate the saved route
19357  {
19358  AllRoutes->RouteTruncateFlag = false; //added at v2.22.0, not truncating any longer so don't want to set SkipForwardLook when setting rearward signals
19359  AllRoutes->StoreOneRoute(3, &ReinstatementRoute);
19361  int RouteNumber = AllRoutes->GetRouteVectorNumber(8, IDInt(RouteID));
19362  AllRoutes->SetAllRearwardsSignals(22, 0, RouteNumber, ReinstatementRoute.PrefDirSize() - 1); //sets signals for the re-instated route
19363  }
19364  if(LastPDElement.AutoSignals)
19365  {
19366  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
19367  }
19368  }
19369 
19370  AllRoutes->CheckMapAndRoutes(5); // test
19371  ReturnFlag = InRouteTrue;
19372  AllRoutes->RouteTruncateFlag = false;
19373  Utilities->CallLogPop(344);
19374 }
19375 
19376 // ---------------------------------------------------------------------------
19377 
19379 {
19380 /*
19381 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
19382 signal.
19383 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
19384  but a new route that is created TO a signal - that signal becomes part of the new route.
19385 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
19386 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
19387  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
19388  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
19389  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
19390  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
19391  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
19392 */
19393 
19394  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
19395  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
19396  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
19397  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
19398  {
19399  Utilities->CallLogPop(2578);
19400  return;
19401  }
19402  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
19403  int RouteColour;
19404  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
19405  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19406  {
19407  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
19408  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
19409  { //found a linked forward route
19410  //check if signal behind this route has been removed from the blue route
19411  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19412  { //signal needs to be added at start of this linked route
19413 
19414  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
19415  if(RouteColour == 1) //red route
19416  {
19417  NewRedFirstPDElement = LastPDElement;
19418  NewRedFirstPDElement.AutoSignals = false;
19419  NewRedFirstPDElement.PrefDirRoute = false;
19420  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19421  NewRedFirstPDElement.IsARoute = true;
19422  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
19423  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
19424  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19425  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19426  {
19427  if(R2MMIt->second.first == int(x))
19428  {
19429  R2MMIt->second.second++;
19430  }
19431  }
19432  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
19433  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19434  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
19435  }
19436  else if(RouteColour == 2) //green route
19437  {
19438  NewGreenFirstPDElement = LastPDElement;
19439  NewGreenFirstPDElement.AutoSignals = false;
19440  NewGreenFirstPDElement.PrefDirRoute = true;
19441  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19442  NewGreenFirstPDElement.IsARoute = true;
19443  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
19444  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
19445  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19446  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19447  {
19448  if(R2MMIt->second.first == int(x))
19449  {
19450  R2MMIt->second.second++;
19451  }
19452  }
19453  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
19454  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19455  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
19456  }
19457  }
19458  break; //no point looking any further
19459  }
19460  }
19461 
19462 //check if there's a linked rearward route missing a signal and if so add it
19463  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19464  {
19465  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
19466  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
19467  { //found a linked rearward route
19468  //check if signal in front of this route has been removed from the blue route
19469  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19470  { //signal needs to be added at end of this linked route
19471 
19472  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
19473  if(RouteColour == 1) //red route
19474  {
19475  NewRedLastPDElement = FirstPDElement;
19476  NewRedLastPDElement.AutoSignals = false;
19477  NewRedLastPDElement.PrefDirRoute = false;
19478  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19479  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
19480  //can use this as adding to the end of the route
19481  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19482  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
19483  }
19484  else if(RouteColour == 2) //green route
19485  {
19486  NewGreenLastPDElement = FirstPDElement;
19487  NewGreenLastPDElement.AutoSignals = false;
19488  NewGreenLastPDElement.PrefDirRoute = true;
19489  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19490  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
19491  //can use this as adding to the end of the route
19492  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19493  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
19494  }
19495  }
19496  break; //no point looking any further
19497  }
19498  }
19499  Utilities->CallLogPop(2579);
19500 }
19501 
19502 // ---------------------------------------------------------------------------
19503 
19505 /*
19506  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
19507  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
19508  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
19509  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
19510  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
19511  the route colours.
19512 */
19513 {
19514  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
19515  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
19517  int RouteNumber;
19518  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
19519  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
19520  //these added at v2.15.0
19521  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19522  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
19523 
19524  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
19525  {
19526  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
19527  {
19528  if(PrefDirVector.at(x).TrackType == SignalPost)
19529  {
19530  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
19531  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
19532  }
19533  }
19534 // AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0); //dropped at v2.17.0 in favour of setting all signals after route removal (see below)
19535  //Fault found on B'ham when train (2A09) exited from Snow Hill terminal platform (no signal) when orce cancelled
19536  //route above, but when rearwards signals set the route to be cancelled still exists, so setting signals first uses
19537  //forward look when it finds a red signal in the route to be cancelled, so first signal in rear route becames yellow
19538  //when should have been be red.
19539 // already set all signals to red in route so start at start of route for further rearwards signal setting <- comment invalid after above
19540  }
19541  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
19542  {
19543  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
19544  }
19545 
19546  if(LastPDElement.AutoSignals) //added at v2.15.0
19547  {
19548  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
19549  }
19550 
19551  if(AllRoutes->AllRoutesVector.size() > 0) //added at v2.17.0 - see above
19552  {
19553  for(TAllRoutes::TAllRoutesVectorIterator ARVIt = AllRoutes->AllRoutesVector.begin(); ARVIt < AllRoutes->AllRoutesVector.end(); ARVIt++)
19554  {
19555  ARVIt->SetRouteSignals(14);
19556  }
19557  }
19558  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
19559  AllRoutes->CheckMapAndRoutes(9); // test
19560  TrainController->BaseTime = TDateTime::CurrentDateTime();
19562  Utilities->CallLogPop(345);
19563  return;
19564 }
19565 
19566 // ---------------------------------------------------------------------------
19567 
19568 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19569 /*
19570  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
19571 */
19572 {
19573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
19574  AnsiString((short)PrefDirRoute));
19575  if(SearchVector.empty())
19576  {
19577  Utilities->CallLogPop(1149);
19578  return;
19579  }
19580  for(unsigned int b = 0; b < SearchVector.size(); b++)
19581  {
19584  PrefDirRoute);
19585  }
19586  Utilities->CallLogPop(346);
19587 }
19588 
19589 // ---------------------------------------------------------------------------
19590 
19591 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19592 /*
19593  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
19594  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
19595  TOneRoute.
19596 */
19597 {
19598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
19599  AnsiString((short)PrefDirRoute));
19600  RouteFlash.RouteFlashVector.clear();
19601  TRouteFlashElement RouteFlashElement;
19602 
19603  for(unsigned int b = 0; b < SearchVector.size(); b++)
19604  {
19605  int H = GetFixedSearchElementAt(11, b).HLoc;
19606  int V = GetFixedSearchElementAt(12, b).VLoc;
19608  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
19609  RouteFlashElement.HLoc = H;
19610  RouteFlashElement.VLoc = V;
19612  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
19613  }
19614  Utilities->CallLogPop(348);
19615 }
19616 
19617 // ---------------------------------------------------------------------------
19618 
19619 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
19620 {
19621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
19622  if(!PrefDirVector.empty())
19623  {
19624  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
19625  {
19626  int H = PrefDirPtr->HLoc;
19627  int V = PrefDirPtr->VLoc;
19628  // check for any LCs that are closed to trains & set the flash values and store in the vector
19629  if(Track->IsLCAtHV(39, H, V))
19630  {
19631  if(Track->IsLCBarrierUpAtHV(0, H, V))
19632  {
19633  Track->LCChangeFlag = true;
19634  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
19635  CLC.HLoc = H;
19636  CLC.VLoc = V;
19638  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
19641  if(PrefDirRoute)
19642  {
19643  CLC.TypeOfRoute = 1;
19644  }
19645  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
19646  Track->ChangingLCVector.push_back(CLC);
19647  }
19648  }
19649  }
19650  }
19651  Utilities->CallLogPop(1948);
19652 }
19653 
19654 // ---------------------------------------------------------------------------
19655 
19657 /*
19658  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19659  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
19660  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19661  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19662 */
19663 {
19664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
19665  if(!OverlayPlotted)
19666  {
19667  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19668  {
19669  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19670  {
19671  continue;
19672  }
19673  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
19674  Display->Update();
19675  }
19676  OverlayPlotted = true;
19677  }
19678  Utilities->CallLogPop(349);
19679 }
19680 
19681 // ---------------------------------------------------------------------------
19682 
19684 /*
19685  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19686  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
19687  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19688  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19689 */
19690 {
19691  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
19692  if(OverlayPlotted)
19693  {
19694  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19695  {
19696  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19697  {
19698  continue;
19699  }
19700  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
19701  Display->Update();
19702  }
19703  OverlayPlotted = false;
19704  }
19705  Utilities->CallLogPop(350);
19706 }
19707 
19708 // ---------------------------------------------------------------------------
19709 
19710 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
19711 {
19712 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
19713 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
19714 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
19715 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
19716 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
19717 messages, and allocate a repair time similar to points)
19718 */
19719 
19720  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
19721  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
19722  {
19723  Utilities->CallLogPop(2528);
19724  return(false);
19725  }
19726  bool FirstSignalFound = false;
19727  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
19728  {
19729  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
19730 //check for a failed point where needs to change to make the route
19731 //shouldn't be any but check to be safe
19732  int Attr = TE.Attribute;
19733  if(PDVIt->TrackType == Points)
19734  {
19735  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
19736  {
19737  if(Attr == 1) //currently set to diverge
19738  {
19739  if(TE.Failed)
19740  {
19741  Utilities->CallLogPop(2529);
19742  return(false); //return without further checking
19743  }
19744  }
19745  }
19746  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
19747  {
19748  if(Attr == 0) //currently set to go straight
19749  {
19750  if(TE.Failed)
19751  {
19752  Utilities->CallLogPop(2530);
19753  return(false); //return without further checking
19754  }
19755  }
19756  }
19757  }
19758  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
19759  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
19760  //the search vector)
19761  int XLinkPosition = PDVIt->XLinkPos;
19762  if(PDVIt->XLinkPos == -1)
19763  {
19764  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
19765  {
19766  for(int x = 0; x < 4; x++)
19767  {
19768  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
19769  {
19770  XLinkPosition = x;
19771  break;
19772  }
19773  }
19774  }
19775  else
19776  {
19777  Utilities->CallLogPop(2549);
19778  return(false); //no point going any further
19779  }
19780  }
19781  if(XLinkPosition > -1) //should be by now but be safe
19782  {
19783  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19784  {
19785  FirstSignalFound = true; //the first signal doesn't change aspect
19786  continue;
19787  }
19788  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19789  {
19790 /*
19791  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
19792  {
19793  continue; //ground signals don't fail
19794  }
19795 */
19796  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
19797  {
19799  IFE.TVPos = PDVIt->TrackVectorPosition;
19800  TE.Failed = true;
19801  TE.Attribute = 0; //stop aspect
19802  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
19803  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
19804  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
19805  " failed when changing aspect.\nTrains can only pass under signaller control.");
19806  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
19807  //set repair time, random value in minutes between 10 and 179
19808  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
19809  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
19810  IFE.RepairTime = RepairTime;
19812  Track->FailedSignalsVector.push_back(IFE);
19814  int RouteNumber; //not used
19815  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
19816  { // 0 for LinkPos ok as a signal so only one track
19817  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
19818  }
19819  Utilities->CallLogPop(2535);
19820  return(true); //return so only allow one failure per route
19821  }
19822  }
19823  }
19824  }
19825  Utilities->CallLogPop(2531);
19826  return(false);
19827 }
19828 
19829 // ---------------------------------------------------------------------------
19830 // ---------------------------------------------------------------------------
19831 
19832 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
19833 {
19834  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
19835  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19836  {
19837  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
19838  }
19839  Utilities->CallLogPop(120);
19840  return(AllRoutesVector.at(At));
19841 }
19842 
19843 // ---------------------------------------------------------------------------
19844 
19846 {
19847  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
19848  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19849  {
19850  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
19851  }
19852  Utilities->CallLogPop(121);
19853  return(AllRoutesVector.at(At));
19854 }
19855 
19856 // ---------------------------------------------------------------------------
19857 
19858 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
19859 /*
19860  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
19861 */
19862 {
19863  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
19864  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19865  {
19866  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
19867  }
19868  Utilities->CallLogPop(351);
19869 }
19870 
19871 // ---------------------------------------------------------------------------
19872 
19873 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
19874 {
19875  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
19876  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19877  {
19878  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
19879  }
19880  Utilities->CallLogPop(1706);
19881 }
19882 
19883 // ---------------------------------------------------------------------------
19884 
19885 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
19886 /*
19887  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
19888  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
19889  Messages are given in TruncateRoute. If successful the route is truncated at and including
19890  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
19891  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
19892  length (train length).
19893 */
19894 {
19895  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
19896  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
19897  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19898  {
19899  TTruncateReturnType ReturnFlag;
19900 // used in SetRearwardsSignalsReturnFalseForTrainInRear (called by TruncateRoute) to skip continuation & buffer attribute change
19901  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
19902  if(ReturnFlag == NotInRoute)
19903  {
19904  continue;
19905  }
19906  else if(ReturnFlag == InRouteTrue)
19907  {
19908  Utilities->CallLogPop(352);
19909  return(true);
19910  }
19911  else if(ReturnFlag == InRouteFalse)
19912  {
19913  Utilities->CallLogPop(353);
19914  return(false);
19915  }
19916  }
19917  Utilities->CallLogPop(354);
19918  return(false);
19919 }
19920 
19921 // ---------------------------------------------------------------------------
19922 
19923 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
19924 /*
19925  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
19926  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
19927 */
19928 {
19929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
19930  AnsiString(LinkPos));
19931  if(TrackVectorPosition == -1) // allows for continuation entries & exits
19932  {
19933  Utilities->CallLogPop(355);
19934  return(false);
19935  }
19936  THVPair Route2MultiMapKeyPair;
19937 
19938  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
19939  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
19940  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19941  TRoute2MultiMapIterator Route2MultiMapIterator;
19942 
19943  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
19944  {
19945  Utilities->CallLogPop(356);
19946  return(false);
19947  }
19948  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
19949  {
19950  Utilities->CallLogPop(1422);
19951  return(true);
19952  }
19953  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
19954  {
19955  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19956 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19957 // realised after writing this that can't be points as would have been covered above, but leave anyway
19958  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
19959  Route2MultiMapIterator->second.second);
19960  EntryLinkPos = PrefDirElement1.ELinkPos;
19961  ExitLinkPos = PrefDirElement1.XLinkPos;
19962  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19963  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19964  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
19965  {
19966  Utilities->CallLogPop(357);
19967  return(true);
19968  }
19969  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
19970  {
19971  Utilities->CallLogPop(358);
19972  return(true);
19973  }
19974  }
19975  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
19976  {
19977  Utilities->CallLogPop(1423);
19978  return(true);
19979  }
19980  Utilities->CallLogPop(363);
19981  return(false); // none found
19982 }
19983 
19984 // ---------------------------------------------------------------------------
19985 
19986 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
19987  Graphics::TBitmap* &EntryDirectionGraphicPtr)
19988 /*
19989  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
19990  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
19991  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
19992  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
19993  for replotting of AutoSigsRoutes.
19994 */
19995 {
19996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
19997  AnsiString(LinkPos));
19998  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19999  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
20000  if(TrackVectorPosition == -1)
20001  {
20002  Utilities->CallLogPop(364);
20003  return(NoRoute); // allows for continuation entries & exits
20004  }
20005  THVPair Route2MultiMapKeyPair;
20006 
20007  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
20008  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
20009  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
20010  TRoute2MultiMapIterator Route2MultiMapIterator;
20011 
20012  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20013  {
20014  Utilities->CallLogPop(365);
20015  return(NoRoute); // none found
20016  }
20017  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20018  {
20019  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20020 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20021  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
20022  Route2MultiMapIterator->second.second);
20023  EntryLinkPos = PrefDirElement1.ELinkPos;
20024  ExitLinkPos = PrefDirElement1.XLinkPos;
20025  EntryLink = PrefDirElement1.Link[EntryLinkPos];
20026  ExitLink = PrefDirElement1.Link[ExitLinkPos];
20027  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
20028  {
20029  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
20030  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
20031  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
20032  {
20033  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
20034  }
20035  if(PrefDirElement1.AutoSignals)
20036  {
20037  Utilities->CallLogPop(366);
20038  return(AutoSigsRoute);
20039  }
20040  else
20041  {
20042  Utilities->CallLogPop(367);
20043  return(NotAutoSigsRoute);
20044  }
20045  }
20046  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
20047  {
20048  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
20049  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
20050  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
20051  {
20052  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
20053  }
20054  if(PrefDirElement1.AutoSignals)
20055  {
20056  Utilities->CallLogPop(368);
20057  return(AutoSigsRoute);
20058  }
20059  else
20060  {
20061  Utilities->CallLogPop(369);
20062  return(NotAutoSigsRoute);
20063  }
20064  }
20065  }
20066  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20067  {
20068  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20069  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20070 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20071  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
20072  EntryLinkPos = PrefDirElement2.ELinkPos;
20073  ExitLinkPos = PrefDirElement2.XLinkPos;
20074  EntryLink = PrefDirElement2.Link[EntryLinkPos];
20075  ExitLink = PrefDirElement2.Link[ExitLinkPos];
20076  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
20077  {
20078  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
20079  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
20080  {
20081  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
20082  }
20083  if(PrefDirElement2.AutoSignals)
20084  {
20085  Utilities->CallLogPop(370);
20086  return(AutoSigsRoute);
20087  }
20088  else
20089  {
20090  Utilities->CallLogPop(371);
20091  return(NotAutoSigsRoute);
20092  }
20093  }
20094  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
20095  {
20096  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
20097  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
20098  {
20099  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
20100  }
20101  if(PrefDirElement2.AutoSignals)
20102  {
20103  Utilities->CallLogPop(372);
20104  return(AutoSigsRoute);
20105  }
20106  else
20107  {
20108  Utilities->CallLogPop(373);
20109  return(NotAutoSigsRoute);
20110  }
20111  }
20112  ItPair.second--; // the second iterator points one past the last matching value
20113  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
20114  EntryLinkPos = PrefDirElement3.ELinkPos;
20115  ExitLinkPos = PrefDirElement3.XLinkPos;
20116  EntryLink = PrefDirElement3.Link[EntryLinkPos];
20117  ExitLink = PrefDirElement3.Link[ExitLinkPos];
20118  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
20119  {
20120  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
20121  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
20122  {
20123  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
20124  }
20125  if(PrefDirElement3.AutoSignals)
20126  {
20127  Utilities->CallLogPop(374);
20128  return(AutoSigsRoute);
20129  }
20130  else
20131  {
20132  Utilities->CallLogPop(375);
20133  return(NotAutoSigsRoute);
20134  }
20135  }
20136  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
20137  {
20138  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
20139  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
20140  {
20141  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
20142  }
20143  if(PrefDirElement3.AutoSignals)
20144  {
20145  Utilities->CallLogPop(376);
20146  return(AutoSigsRoute);
20147  }
20148  else
20149  {
20150  Utilities->CallLogPop(377);
20151  return(NotAutoSigsRoute);
20152  }
20153  }
20154  }
20155  Utilities->CallLogPop(378);
20156  return(NoRoute); // none found
20157 }
20158 
20159 // ---------------------------------------------------------------------------
20160 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
20161 /*
20162  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
20163  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
20164 */
20165 {
20166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
20167  AnsiString(LinkPos));
20168  if(TrackVectorPosition == -1)
20169  {
20170  RouteNumber = -1;
20171  Utilities->CallLogPop(379);
20172  return(NoRoute); // allows for continuation & buffer entries & exits
20173  }
20174  THVPair Route2MultiMapKeyPair;
20175 
20176  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
20177  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
20178  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
20179  TRoute2MultiMapIterator Route2MultiMapIterator;
20180 
20181  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20182  {
20183  RouteNumber = -1;
20184  Utilities->CallLogPop(380);
20185  return(NoRoute); // none found
20186  }
20187  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20188  {
20189  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20190 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20191  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
20192  Route2MultiMapIterator->second.second);
20193  EntryLinkPos = PrefDirElement1.ELinkPos;
20194  ExitLinkPos = PrefDirElement1.XLinkPos;
20195  EntryLink = PrefDirElement1.Link[EntryLinkPos];
20196  ExitLink = PrefDirElement1.Link[ExitLinkPos];
20197  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
20198  {
20199  RouteNumber = Route2MultiMapIterator->second.first;
20200  if(PrefDirElement1.AutoSignals)
20201  {
20202  Utilities->CallLogPop(381);
20203  return(AutoSigsRoute);
20204  }
20205  else
20206  {
20207  Utilities->CallLogPop(382);
20208  return(NotAutoSigsRoute);
20209  }
20210  }
20211  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
20212  {
20213  RouteNumber = Route2MultiMapIterator->second.first;
20214  if(PrefDirElement1.AutoSignals)
20215  {
20216  Utilities->CallLogPop(383);
20217  return(AutoSigsRoute);
20218  }
20219  else
20220  {
20221  Utilities->CallLogPop(384);
20222  return(NotAutoSigsRoute);
20223  }
20224  }
20225  }
20226  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20227  {
20228  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20229  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20230 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20231  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
20232  EntryLinkPos = PrefDirElement2.ELinkPos;
20233  ExitLinkPos = PrefDirElement2.XLinkPos;
20234  EntryLink = PrefDirElement2.Link[EntryLinkPos];
20235  ExitLink = PrefDirElement2.Link[ExitLinkPos];
20236  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
20237  {
20238  RouteNumber = ItPair.first->second.first;
20239  if(PrefDirElement2.AutoSignals)
20240  {
20241  Utilities->CallLogPop(385);
20242  return(AutoSigsRoute);
20243  }
20244  else
20245  {
20246  Utilities->CallLogPop(386);
20247  return(NotAutoSigsRoute);
20248  }
20249  }
20250  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
20251  {
20252  RouteNumber = ItPair.first->second.first;
20253  if(PrefDirElement2.AutoSignals)
20254  {
20255  Utilities->CallLogPop(387);
20256  return(AutoSigsRoute);
20257  }
20258  else
20259  {
20260  Utilities->CallLogPop(388);
20261  return(NotAutoSigsRoute);
20262  }
20263  }
20264  ItPair.second--; // the second iterator points one past the last matching value
20265  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
20266  EntryLinkPos = PrefDirElement3.ELinkPos;
20267  ExitLinkPos = PrefDirElement3.XLinkPos;
20268  EntryLink = PrefDirElement3.Link[EntryLinkPos];
20269  ExitLink = PrefDirElement3.Link[ExitLinkPos];
20270  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
20271  {
20272  RouteNumber = ItPair.second->second.first;
20273  if(PrefDirElement3.AutoSignals)
20274  {
20275  Utilities->CallLogPop(389);
20276  return(AutoSigsRoute);
20277  }
20278  else
20279  {
20280  Utilities->CallLogPop(390);
20281  return(NotAutoSigsRoute);
20282  }
20283  }
20284  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
20285  {
20286  RouteNumber = ItPair.second->second.first;
20287  if(PrefDirElement3.AutoSignals)
20288  {
20289  Utilities->CallLogPop(391);
20290  return(AutoSigsRoute);
20291  }
20292  else
20293  {
20294  Utilities->CallLogPop(392);
20295  return(NotAutoSigsRoute);
20296  }
20297  }
20298  }
20299  RouteNumber = -1;
20300  Utilities->CallLogPop(393);
20301  return(NoRoute); // none found
20302 }
20303 
20304 // ---------------------------------------------------------------------------
20305 
20306 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
20307 /*
20308  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
20309  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
20310  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
20311  and Route2MultiMap.
20312 */
20313 {
20314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
20315  TOneRoute EmptyRoute;
20316 
20317  EmptyRoute.RouteID = NextRouteID;
20318  NextRouteID++;
20319 
20320  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
20321  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
20322  {
20323  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
20324  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
20325  }
20326  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
20327  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
20328  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
20329  Utilities->CallLogPop(394);
20330 }
20331 
20332 // ---------------------------------------------------------------------------
20333 
20335 /*
20336  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
20337  that is already in Route is used.
20338 */
20339 {
20340  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
20341  TOneRoute EmptyRoute;
20342 
20343  EmptyRoute.RouteID = Route->RouteID;
20344 
20345  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
20346  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
20347  {
20348  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
20349  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
20350  }
20351  Utilities->CallLogPop(1579);
20352 }
20353 
20354 // ---------------------------------------------------------------------------
20355 
20356 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
20357 /*
20358  When attaching a new route section to an existing route, it is sometimes necessary to erase the
20359  original route and create a new composite route. This function Erases all elements in the route
20360  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
20361  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
20362  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
20363  that are greater than the route number that is removed. The LockedRouteVector as also searched
20364  and if any relate to the route that has been cleared they are erased too, but the fact that one
20365  has been found is recorded so that it can be re-established later.
20366 */
20367 {
20368  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
20369  THVPair Route2MultiMapKeyPair;
20370  TRoute2MultiMapEntry Route2MultiMapEntry;
20371  TRoute2MultiMapIterator Route2MultiMapIterator;
20372 
20373 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
20374 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
20375 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
20376 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
20377 // If so the locked route is removed from the locked vector and is lost.
20378  LockedRouteRearTrackVectorPosition = 0;
20379  LockedRouteLastTrackVectorPosition = 0;
20380  LockedRouteLastXLinkPos = 0;
20381  LockedRouteLockStartTime = TDateTime(0);
20382  if(!LockedRouteVector.empty())
20383  {
20384  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20385  {
20386  if(LRVIT->RouteNumber == RouteNumber)
20387  {
20388  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
20389  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
20390  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
20391  LockedRouteLockStartTime = LRVIT->LockStartTime;
20392  LockedRouteFoundDuringRouteBuilding = true;
20393  LockedRouteVector.erase(LRVIT);
20394  }
20395  }
20396  }
20397  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
20398  {
20399  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
20400  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
20401  }
20402  Utilities->CallLogPop(395);
20403 }
20404 
20405 // ---------------------------------------------------------------------------
20406 
20408  TRoute2MultiMapIterator &Route2MultiMapIterator)
20409 /*
20410  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
20411  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
20412  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
20413  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
20414  are given for failure.
20415 */
20416 {
20417  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20418  AnsiString(VLoc) + "," + AnsiString(ELink));
20419  TRouteElementPair ReturnPair;
20420 
20421  ReturnPair.first = -1;
20422  ReturnPair.second = 0;
20423  THVPair Route2MultiMapKeyPair;
20424 
20425  Route2MultiMapKeyPair.first = HLoc;
20426  Route2MultiMapKeyPair.second = VLoc;
20427  TRoute2MultiMapEntry Route2MultiMapEntry;
20428 
20429  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20430  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20431 
20432  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20433  Route2MultiMapIterator = ItPair.first;
20434 
20435  if(ItPair.first == ItPair.second)
20436  {
20437  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
20438  }
20439  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
20440  {
20441  ReturnPair.first = ItPair.first->second.first;
20442  ReturnPair.second = ItPair.first->second.second;
20443  Route2MultiMapIterator = ItPair.first;
20444  Utilities->CallLogPop(396);
20445  return(ReturnPair);
20446  }
20447  ItPair.first++;
20448  if(ItPair.first == ItPair.second)
20449  {
20450  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
20451  }
20452  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
20453  {
20454  ReturnPair.first = ItPair.first->second.first;
20455  ReturnPair.second = ItPair.first->second.second;
20456  Route2MultiMapIterator = ItPair.first;
20457  Utilities->CallLogPop(397);
20458  return(ReturnPair);
20459  }
20460  Utilities->CallLogPop(398);
20461  return(ReturnPair);
20462 }
20463 
20464 // ---------------------------------------------------------------------------
20465 
20466 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
20467 /*
20468  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
20469  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
20470  RouteNumber (route position in AllRoutes vector is returned as a reference.
20471  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
20472  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
20473 */
20474 {
20475  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
20476  AnsiString(VLoc) + "," + AnsiString(ELink));
20477  THVPair Route2MultiMapKeyPair;
20478 
20479  Route2MultiMapKeyPair.first = HLoc;
20480  Route2MultiMapKeyPair.second = VLoc;
20481  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20482 
20483  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20484 
20485  if(ItPair.first == ItPair.second)
20486  {
20487  RouteNumber = -1;
20488  Utilities->CallLogPop(2032);
20489  return(false);
20490  }
20491  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
20492  {
20493  RouteNumber = ItPair.first->second.first;
20494  Utilities->CallLogPop(2033);
20495  return(true);
20496  }
20497  ItPair.first++;
20498 
20499  if(ItPair.first == ItPair.second)
20500  {
20501  RouteNumber = -1;
20502  Utilities->CallLogPop(2034);
20503  return(false);
20504  }
20505  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
20506  {
20507  RouteNumber = ItPair.first->second.first;
20508  Utilities->CallLogPop(2035);
20509  return(true);
20510  }
20511  RouteNumber = -1;
20512  Utilities->CallLogPop(2036);
20513  return(false);
20514 }
20515 
20516 // ---------------------------------------------------------------------------
20517 
20518 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
20519 /*
20520  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
20521  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
20522  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
20523  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
20524  Called by TAllRoutes::AddRouteElement.
20525 */
20526 {
20527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20528  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
20529  THVPair Route2MultiMapKeyPair;
20530 
20531  Route2MultiMapKeyPair.first = HLoc;
20532  Route2MultiMapKeyPair.second = VLoc;
20533  TRoute2MultiMapEntry Route2MultiMapEntry;
20534 
20535  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20536  TRouteElementPair RouteElementPair;
20537 
20538  RouteElementPair.first = RouteNumber;
20539  RouteElementPair.second = RouteElementNumber;
20540  Route2MultiMapEntry.second = RouteElementPair;
20541 
20542  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
20543  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
20544  {
20545  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
20546  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
20547  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
20548  {
20549  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
20550  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
20551  {
20552  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20553  }
20554  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
20555  }
20556  else
20557  // same ELink so have an error
20558  {
20559  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20560  }
20561  }
20562  else
20563  {
20564  Route2MultiMap.insert(Route2MultiMapEntry);
20565  }
20566 // element at H&V not found in map so insert it
20567  Utilities->CallLogPop(399);
20568 }
20569 
20570 // ---------------------------------------------------------------------------
20571 
20573 /*
20574  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
20575  and the second in the reference SecondPair. If there's only one then it's the function return
20576 */
20577 {
20578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20579  AnsiString(VLoc));
20581 
20582  TempPair.first = -1;
20583  TempPair.second = 0;
20584  SecondPair = TempPair;
20585  TRoute2MultiMapIterator Route2MultiMapIterator;
20586  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
20587  THVPair Route2MultiMapKeyPair;
20588 
20589  Route2MultiMapKeyPair.first = HLoc;
20590  Route2MultiMapKeyPair.second = VLoc;
20591  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20592  {
20593  Utilities->CallLogPop(400);
20594  return(TempPair);
20595  }
20596  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20597  {
20598  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20599  Utilities->CallLogPop(401);
20600  return(Route2MultiMapIterator->second);
20601  }
20602  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20603  {
20604  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20605  TempPair = ItRange.first->second;
20606  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
20607  Utilities->CallLogPop(402);
20608  return(TempPair);
20609  }
20610  Utilities->CallLogPop(403);
20611  return(TempPair);
20612 }
20613 
20614 // ---------------------------------------------------------------------------
20615 
20616 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
20617 /*
20618  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
20619  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
20620 */
20621 {
20622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
20623  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
20624  {
20625  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
20626  {
20627  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
20628  TAllRoutes::TRouteElementPair SecondPair;
20629  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
20630  if(RouteElementPair.first == -1)
20631  // failed to find element in multimap
20632  {
20633  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
20634  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
20635  }
20636  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
20637  // neither pair has expected route number
20638  {
20639  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20640  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
20641  (AnsiString)Caller);
20642  }
20643  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
20644  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
20645  {
20646  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20647  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
20648  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
20649  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
20650  }
20651  }
20652  }
20653  unsigned int SizeVal = 0;
20654 
20655 // check map and sum of route sizes match
20656  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20657  {
20658  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
20659  }
20660  if(SizeVal != Route2MultiMap.size())
20661  {
20662  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
20663  (AnsiString)Caller);
20664  }
20665  Utilities->CallLogPop(404);
20666  return;
20667 }
20668 
20669 // ---------------------------------------------------------------------------
20670 
20671 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
20672 /*
20673  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
20674  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
20675  exceed that for the erased route. Where this is so the RouteNumber is decremented.
20676 */
20677 {
20678  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
20679  if(!Route2MultiMap.empty())
20680  {
20681  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20682  {
20683  if(Route2MultiMapIterator->second.first > RouteNumber)
20684  {
20685  Route2MultiMapIterator->second.first--;
20686  }
20687  }
20688  }
20689  Utilities->CallLogPop(405);
20690 }
20691 
20692 // ---------------------------------------------------------------------------
20693 
20694 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
20695 /*
20696  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
20697  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
20698  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
20699 */
20700 {
20701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
20702  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
20703  if(!Route2MultiMap.empty())
20704  {
20705  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20706  {
20707  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
20708  {
20709  Route2MultiMapIterator->second.second--;
20710  }
20711  }
20712  }
20713  Utilities->CallLogPop(406);
20714 }
20715 
20716 // ---------------------------------------------------------------------------
20717 
20718 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
20719 /*
20720  Erases the route element from Route2MultiMap and from the PrefDirVector.
20721  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
20722  decremented if they are greater than the element number removed, and if the entire route is removed
20723  then the route numbers are also decremented in the map for route numbers that are greater than the route
20724  number that is removed.
20725 */
20726 {
20727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20728  AnsiString(ELink));
20729  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
20730  TRoute2MultiMapIterator Route2MultiMapIterator;
20731 
20732  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
20733  if(RequiredRoutePair.first == -1)
20734  {
20735  throw Exception("Failed to find route element in RemoveRouteElement");
20736  }
20737  Route2MultiMap.erase(Route2MultiMapIterator);
20738  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
20739 
20740 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
20741  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
20742 
20743  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
20744  {
20745  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
20746  }
20747 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
20748 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
20749 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
20750 // to check if a route element is present, and the element has already been removed from the map - see above.
20751 
20752 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
20753 /*
20754  int LockedVectorNumber = -1;
20755  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
20756  {
20757  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
20758  }
20759 */
20760 
20761 // erase element from route
20762  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
20763 // CheckMapAndRoutes();//test - drop - tested below
20764 
20765 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
20766 // be so as continuation exit is at the end of the route, and truncation is from the end
20768  {
20770  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20771  AutoSigVectorIT--)
20772  {
20773  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
20774  {
20775  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
20776  }
20777  }
20778  }
20779 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
20780 // and adjust all the corresponding route numbers
20781  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
20782  {
20783  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
20784  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
20785  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
20786 
20787 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
20788  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
20789  it is erased then - see TInterface::ApproachLocking
20790 
20791  if(LockedVectorNumber > -1)
20792  {
20793  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
20794  }
20795 */
20796  // decrement route numbers in the locked route vector whether or not this route is a locked route
20797  if(!LockedRouteVector.empty())
20798  {
20799  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20800  {
20801  if(LRVIT->RouteNumber > RequiredRoutePair.first)
20802  {
20803  LRVIT->RouteNumber--;
20804  }
20805  }
20806  }
20808  {
20810  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20811  AutoSigVectorIT--)
20812  {
20813  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
20814  {
20815  AutoSigVectorIT->RouteNumber--;
20816  }
20817  }
20818  }
20819  }
20820  CheckMapAndRoutes(7); // test
20821  Utilities->CallLogPop(407);
20822 }
20823 
20824 // ---------------------------------------------------------------------------
20825 
20826 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
20827 /*
20828  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
20829  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
20830  since that catches all route elements wherever created
20831 */
20832 {
20833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20834  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
20835  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
20836  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
20837  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
20838 } //number is one less than this
20839 
20840 // ---------------------------------------------------------------------------
20841 
20842 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
20843 /*
20844  Enter with signal at TrackVectorElement already set to red by the passing train.
20845  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
20846  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
20847  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
20848  case the function sets no further signals - if rear route is non-autosigs then no route behind train, if autosigs the train will have
20849  set signals in rear as it passed them.
20850 */
20851 {
20852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
20853  "," + AnsiString(XLinkPos));
20854  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
20855  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
20856 
20857  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
20858  if(RouteElementPair.first == -1)
20859  {
20860  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
20861  }
20862  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
20863 
20864  RequiredPair = RouteElementPair;
20865  if(RouteElement.XLinkPos != XLinkPos)
20866  {
20867  if(SecondPair.first != -1)
20868  {
20869  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
20870  RequiredPair = SecondPair;
20871  if(RouteElement.XLinkPos != XLinkPos)
20872  {
20873  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
20874  }
20875  }
20876  else
20877  {
20878  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
20879  }
20880  }
20881 // new function
20882  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
20883  Utilities->CallLogPop(409);
20884 }
20885 
20886 // ---------------------------------------------------------------------------
20887 
20888 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber) //minor changes at v2.17.0
20889 /*
20890  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
20891  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
20892  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
20893  accordingly, then double yellow, then green (for 4 aspect signals). There are only 3 calls in all for any given route, and the AccessNumber
20894  changes from 0 to 1 to 2 for successive calls.
20895  Initially Attribute is set to AccessNumber to correspond to the first signal attribute to be set, then a number of validity checks
20896  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
20897  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
20898  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals - if rear
20899  route is non-autosigs then no route behind train, if autosigs the train will have set signals in rear as it passes them.
20900 */
20901 {
20902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
20903  AnsiString(AccessNumber));
20904  TPrefDirElement RouteElement;
20905  int Attribute = AccessNumber; //was +1, but at v2.17.0 access no. increment carried out before set signals so SetRouteSignals works ok whenever called
20906 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
20907  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
20908 
20909  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
20910  {
20911  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
20912  }
20913  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
20914  {
20915  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
20916  }
20917  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
20918  x).XLinkPos] != End)
20919  {
20920  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
20921  }
20922 // new function
20923  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
20924  Utilities->CallLogPop(410);
20925 }
20926 
20927 // ---------------------------------------------------------------------------
20928 
20929 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition) //some changes at v2.17.0
20930 /*
20931  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
20932  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
20933  or (b) in a linked rear route, in which case the function sets no further signals - if rear route is non-autosigs then no route behind train,
20934  if autosigs the train will have set signals in rear as it passed them.
20935 
20936  First call SetRearwardsSignalsReturnFalseForTrainInRear (which is only called by this function) to set signals in route RouteNumber according
20937  to the received or modified (because of the forward look for buffers or continuation etc.) Attribute. If no train is found during this call
20938  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrainInRear for each rearwards linked route (without a forward look)
20939  until either reach the beginning of the last linked route or find a train in a linked rear route. If a train is found in a linked rear route
20940  then the function terminates.
20941 
20942  However if a train is found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrainInRear then need to continue after the
20943  train for an autosigs route or in case had just added a route segment behind a train that now forms part of a single continuous route for a
20944  non-autosigs route, otherwise the signals won't be set behind the train.
20945 
20946  First the route is examined element by element from the RouteStartPosition towards the start of the
20947  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
20948  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
20949  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
20950  found behind the train.
20951 
20952  Description of SetRearwardsSignalsReturnFalseForTrainInRear for reference
20953  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
20954  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
20955  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
20956  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
20957  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
20958  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
20959  or (c) truncating a route.
20960 
20961  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
20962  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
20963  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
20964  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
20965  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
20966  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
20967  the function returns true.
20968 
20969  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
20970  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
20971 */
20972 {
20973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
20974  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
20975  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
20976  int RearwardLinkedRouteNumber;
20977 
20978 // Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes {dropped at v2.17.0 as not used)
20979  bool SkipForwardLook = false; //allow forward look in first call
20980  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(1, Attribute, RouteStartPosition, SkipForwardLook)) // updates
20981  //Attribute to 1+ final signal value in the route for use in further linked routes
20982  {
20983  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1 (no
20984  { //linked rearwards route)
20985  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20986  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute) //keep setting signals on each rear route until find a train or no more routes
20987  {
20988  SkipForwardLook = true; //don't want forward look for subsequent rearwards linked routes
20989  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(2, Attribute, AllRoutes->GetFixedRouteAt(130,
20990  RearwardLinkedRouteNumber).PrefDirSize() - 1, SkipForwardLook)))
20991  {
20992  break;
20993  }
20994  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
20995  }
20996  }
20997  }
20998  else // found a train in this route (in RouteNumber) before the beginning of the route, so need to continue setting signals after the train
20999  {
21000  int TrainID, TrainPosition, BehindTrainPosition;
21001  bool FoundTrain = false, BehindTrain = false;
21002  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
21003  {
21004  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
21005  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
21006  TrainID = TrackElement.TrainIDOnElement;
21007  if(TrackElement.TrackType == Bridge)
21008  {
21009  if(PrefDirElement.XLinkPos < 2)
21010  {
21011  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21012  }
21013  else
21014  {
21015  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21016  }
21017  }
21018  if(TrainID == -1)
21019  {
21020  continue;
21021  }
21022  else
21023  {
21024  FoundTrain = true;
21025  TrainPosition = x;
21026  break;
21027  }
21028  }
21029  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then this route doesn't continue behind the train so can stop.
21030  { //If there is a linked rear route then no need to deal with signals behind train here -
21031  //if rear route is non-autosigs then no route behind train, if autosigs the train will have
21032  //set signals in rear as it passed them.
21033  for(int x = TrainPosition; x >= 0; x--) // now step back from that position until find element behind the train - ignore any
21034  { // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
21035  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
21036  // need the element behind the rearmost train.
21037  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
21038  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
21039  TrainID = TrackElement.TrainIDOnElement;
21040  if(TrackElement.TrackType == Bridge)
21041  {
21042  if(PrefDirElement.XLinkPos < 2)
21043  {
21044  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21045  }
21046  else
21047  {
21048  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21049  }
21050  }
21051  if(TrainID != -1)
21052  {
21053  continue; // still on train
21054  }
21055  else
21056  {
21057  BehindTrain = true;
21058  BehindTrainPosition = x;
21059  break;
21060  }
21061  }
21062  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
21063  // so on for as many trains as there are on this (RouteNumber) route
21064  {
21065  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // Although SkipForwardLook will be false when
21066  //SetRearwardsSignalsReturnFalseForTrainInRear is first called the forward look will find the train so Attribute will be set to 0
21067  } //for rearward signal setting
21068  }
21069  }
21070  Utilities->CallLogPop(411);
21071 }
21072 
21073 // ---------------------------------------------------------------------------
21074 
21075 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
21076 {
21077 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
21078 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
21079 rearmost linked route) - this because train cancels route elements that it touches)
21080 */
21081  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
21082  AnsiString(LookBackwardsFromHere));
21083  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
21084  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
21085  TPrefDirElement PrefDirElement, FirstElement;
21086  TTrackElement TrackElement;
21087  bool ExamineRoute = true;
21088 
21089  while(ExamineRoute)
21090  {
21091  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
21092  {
21093  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
21094  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
21095  TrainID = TrackElement.TrainIDOnElement;
21096  if(TrackElement.TrackType == Bridge)
21097  {
21098  if(PrefDirElement.XLinkPos < 2)
21099  {
21100  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21101  }
21102  else
21103  {
21104  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21105  }
21106  }
21107  if(TrainID > -1)
21108  {
21109  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
21110  {
21111  //any trains further back in route will be protected by the red signal behind the stopped train
21112  Utilities->CallLogPop(412);
21113  return(false);
21114  }
21115  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
21116  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
21117  //other way & can cancel the route
21118  {
21119  Utilities->CallLogPop(2203);
21120  return(false);
21121  }
21122  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
21123  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
21124  }
21125  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
21126  {
21127  if(TrackElement.Attribute == 0)
21128  {
21129  Utilities->CallLogPop(413);
21130  return(false); // OK, red signal in front of a train
21131  }
21132  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
21133  {
21134  SignalCount++;
21135  }
21136  if(SignalCount >= 3)
21137  {
21138  Utilities->CallLogPop(414);
21139  return(false);
21140  }
21141  }
21142  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
21143  // ElinkPos because working back along PrefDir to beginning
21144  {
21145  Utilities->CallLogPop(415);
21146  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
21147  }
21148  }
21149  //now look at linked rearwards routes
21150  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
21151  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
21152  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
21153  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
21154  {
21155  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
21156  ExamineRoute = true;
21157  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
21158  }
21159  else
21160  {
21161  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
21162  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
21163  TrainID = PriorTrackElement.TrainIDOnElement;
21164  if(PriorTrackElement.TrackType == Bridge)
21165  {
21166  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
21167  {
21168  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21169  }
21170  else
21171  {
21172  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21173  }
21174  }
21175  if(TrainID > -1)
21176  {
21177  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
21178  {
21179  Utilities->CallLogPop(748);
21180  return(false);
21181  }
21182  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
21183  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
21184  //other way & can cancel the route
21185  {
21186  Utilities->CallLogPop(2204);
21187  return(false);
21188  }
21189  Utilities->CallLogPop(1962);
21190  return(true); //otherwise need to lock the route
21191  }
21192  ExamineRoute = false;
21193  }
21194  }
21195 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
21196 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
21197  Utilities->CallLogPop(416);
21198  return(false);
21199 }
21200 
21201 // ---------------------------------------------------------------------------
21202 
21203 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
21204  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
21205 {
21206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
21207  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
21208  TPrefDirElement InternalPrefDirElement; // blank element
21209 
21210  PrefDirElement = InternalPrefDirElement;
21211  if(LockedRouteVector.empty())
21212  {
21213  Utilities->CallLogPop(417);
21214  return(false);
21215  }
21216 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
21217 // even if some elements have been removed from the front by a train
21218  bool InLockedRoute = false;
21219 
21220  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
21221  {
21222  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
21223  {
21224  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
21225  // doesn't arise)
21226  InLockedRoute = true;
21227  break;
21228  }
21229  }
21230  if(!InLockedRoute)
21231  {
21232  Utilities->CallLogPop(418);
21233  return(false);
21234  }
21235  int RouteNumber, VectorCount = 0;
21236  TRouteType RouteType;
21237 
21238  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
21239  {
21240  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
21241  if(RouteType == NoRoute)
21242  {
21243  continue;
21244  }
21245 /* can't use this test with front truncation
21246  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
21247  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
21248  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
21249  {
21250  throw Exception
21251  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
21252  }
21253 */
21254  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
21255  {
21256  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
21257  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
21258  {
21259  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
21260  {
21261  PrefDirElement = InternalPrefDirElement;
21262  LockedVectorNumber = VectorCount;
21263  Utilities->CallLogPop(419);
21264  return(true);
21265  }
21266  }
21267  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
21268  {
21269  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
21270  {
21271  PrefDirElement = InternalPrefDirElement;
21272  LockedVectorNumber = VectorCount;
21273  Utilities->CallLogPop(420);
21274  return(true);
21275  }
21276  else
21277  {
21278  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
21279  }
21280  }
21281  }
21282  VectorCount++;
21283  }
21284  Utilities->CallLogPop(421);
21285  return(false);
21286 }
21287 
21288 // ---------------------------------------------------------------------------
21289 
21291 {
21292  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
21293  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21294  {
21295  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
21296  {
21297  Utilities->CallLogPop(963);
21298  return(x);
21299  }
21300  }
21301  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
21302 }
21303 
21304 // ---------------------------------------------------------------------------
21305 
21307 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
21308 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
21309 {
21310  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
21311  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21312  {
21313  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
21314  {
21315  Utilities->CallLogPop(2039);
21316  return(true);
21317  }
21318  }
21319  Utilities->CallLogPop(2040);
21320  return(false);
21321 }
21322 
21323 // ---------------------------------------------------------------------------
21324 
21326 {
21327  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
21328  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21329  {
21330  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
21331  {
21332  Utilities->CallLogPop(964);
21333  return(GetFixedRouteAt(159, x));
21334  }
21335  }
21336  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
21337 }
21338 
21339 // ---------------------------------------------------------------------------
21340 
21342 {
21343  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
21344  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21345  {
21346  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
21347  {
21348  Utilities->CallLogPop(965);
21349  return(GetModifiableRouteAt(15, x));
21350  }
21351  }
21352  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
21353 }
21354 
21355 // ---------------------------------------------------------------------------
21356 
21357 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
21358 {
21359  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
21360  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
21361  Utilities->SaveFileInt(OutFile, NextRouteID);
21362  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21363  {
21364  TOneRoute OneRoute = GetFixedRouteAt(165, x);
21365  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
21366  OneRoute.SavePrefDirVector(6, OutFile);
21367  }
21368  Utilities->CallLogPop(1442);
21369 }
21370 
21371 // ---------------------------------------------------------------------------
21372 
21373 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
21374 {
21375  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
21376  int NumberOfRoutes;
21377 
21378  NumberOfRoutes = Utilities->LoadFileInt(InFile);
21379  NextRouteID = Utilities->LoadFileInt(InFile);
21380  for(int x = 0; x < NumberOfRoutes; x++)
21381  {
21382  TOneRoute OneRoute; // empty route
21383  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
21384  OneRoute.LoadPrefDir(2, InFile);
21386  {
21387  StoreOneRouteAfterSessionLoad(0, &OneRoute);
21388  }
21389  else
21390  {
21391  Utilities->CallLogPop(1443);
21392  return(false);
21393  }
21394  }
21395  Utilities->CallLogPop(1444);
21396  return(true);
21397 }
21398 
21399 // ---------------------------------------------------------------------------
21400 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
21401 {
21402  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
21403  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
21404 
21405  if((NumberOfRoutes < 0) || (NumberOfRoutes > 10000)) //increased from 5000 to 10000 at v2.20.3 because of Jason B's WCML railway (was 304 but could get higher)
21406  {
21407  Utilities->CallLogPop(1445);
21408  return(false);
21409  }
21410  int NextID = Utilities->LoadFileInt(InFile);
21411 
21412  if((NextID < 0) || (NextID > 1000000))
21413  {
21414  Utilities->CallLogPop(1446);
21415  return(false);
21416  }
21417  for(int x = 0; x < NumberOfRoutes; x++)
21418  {
21419  int RouteID = Utilities->LoadFileInt(InFile);
21420  if((RouteID < 0) || (RouteID > 1000000)) //increased from 20000 t0 1000000 at v2.20.3 because of Jason B's WCML railway where RouteID was 22009
21421  {
21422  Utilities->CallLogPop(1447);
21423  return(false);
21424  }
21425  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
21426  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
21427  {
21428  Utilities->CallLogPop(1448);
21429  return(false);
21430  }
21431  }
21432  Utilities->CallLogPop(1449);
21433  return(true);
21434 }
21435 
21436 // ---------------------------------------------------------------------------
21437 
21438 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
21439 {
21440  // return true for a loop
21441  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
21442  AnsiString(StartPosition));
21443  if(EndPosition == StartPosition)
21444  {
21445  Utilities->CallLogPop(1839);
21446  return(true); // shouldn't happen but treat as a loop if does
21447  }
21448 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
21449  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
21450  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
21451 
21452  while(TrackIsInARoute(15, TVPos, LkPos))
21453  {
21454  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
21455  int NewLkPos = -1;
21456  if(NewTVPos > -1)
21457  {
21458  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
21459  if(NewLkPos == -1)
21460  {
21461  Utilities->CallLogPop(1840);
21462  return(true); // shouldn't arise but treat as loop if does
21463  }
21464  }
21465  else // reached a buffer or continuation
21466  {
21467  Utilities->CallLogPop(1841);
21468  return(false);
21469  }
21470 //Error found by Xeon notified by email 13/10/20.
21471 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
21472 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
21473 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
21474 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
21475 //New check added for v2.6.0
21476 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
21477 //as possible in case there are other unforeseen effects.
21478  int RouteNumber; //dummy, not used
21479  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
21480  {
21481  Utilities->CallLogPop(2241);
21482  return(false);
21483  }
21484  //now make the connected element the current element, read across the TV number and determine the exit link
21485  TVPos = NewTVPos;
21486  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
21487  {
21488  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
21489  {
21490  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
21491  {
21492  LkPos = 1;
21493  }
21494  else
21495  {
21496  LkPos = 3;
21497  }
21498  }
21499  else
21500  {
21501  LkPos = 0;
21502  }
21503  }
21504  else
21505  {
21506  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
21507  }
21508  if(TVPos == StartPosition)
21509  {
21510  Utilities->CallLogPop(1842);
21511  return(true); // it is a loop
21512  }
21513  }
21514  Utilities->CallLogPop(1843);
21515  return(false); // reached end of route so not a loop
21516 }
21517 
21518 // ---------------------------------------------------------------------------
21519 
21520 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21521 /*
21522  Track geometry allows diagonals to cross without occupying the same track element, so when
21523  route plotting it is necessary to check if there is an existing route or a train on such a crossing
21524  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
21525  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21526  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21527  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21528  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21529  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21530  Each of these is examined in turn for each route element in the relevant position.
21531 
21532  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
21533  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
21534  that returns false in all cases (including elements & links not present) except train present.
21535 */
21536 {
21537  int TrainID; // not used in this function
21538 
21539  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
21540  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
21541  TPrefDirElement TempPrefDirElement;
21542  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21543 
21544  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
21545  if(FirstPair.first > -1)
21546  {
21547  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
21548  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21549  {
21550  Utilities->CallLogPop(310);
21551  return(true);
21552  }
21553  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21554  {
21555  Utilities->CallLogPop(311);
21556  return(true);
21557  }
21558  }
21559  if(SecondPair.first > -1)
21560  {
21561  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
21562  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21563  {
21564  Utilities->CallLogPop(312);
21565  return(true);
21566  }
21567  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21568  {
21569  Utilities->CallLogPop(313);
21570  return(true);
21571  }
21572  }
21573  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
21574  9, TrainID)))
21575  {
21576  Utilities->CallLogPop(1997);
21577  return(true);
21578  }
21579  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
21580  if(FirstPair.first > -1)
21581  {
21582  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
21583  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21584  {
21585  Utilities->CallLogPop(314);
21586  return(true);
21587  }
21588  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21589  {
21590  Utilities->CallLogPop(315);
21591  return(true);
21592  }
21593  }
21594  if(SecondPair.first > -1)
21595  {
21596  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
21597  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21598  {
21599  Utilities->CallLogPop(316);
21600  return(true);
21601  }
21602  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21603  {
21604  Utilities->CallLogPop(317);
21605  return(true);
21606  }
21607  }
21608  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
21609  9, TrainID)))
21610  {
21611  Utilities->CallLogPop(1998);
21612  return(true);
21613  }
21614  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
21615  if(FirstPair.first > -1)
21616  {
21617  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
21618  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21619  {
21620  Utilities->CallLogPop(318);
21621  return(true);
21622  }
21623  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21624  {
21625  Utilities->CallLogPop(319);
21626  return(true);
21627  }
21628  }
21629  if(SecondPair.first > -1)
21630  {
21631  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
21632  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21633  {
21634  Utilities->CallLogPop(320);
21635  return(true);
21636  }
21637  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21638  {
21639  Utilities->CallLogPop(321);
21640  return(true);
21641  }
21642  }
21643  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
21644  7, TrainID)))
21645  {
21646  Utilities->CallLogPop(1999);
21647  return(true);
21648  }
21649  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
21650  if(FirstPair.first > -1)
21651  {
21652  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
21653  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21654  {
21655  Utilities->CallLogPop(322);
21656  return(true);
21657  }
21658  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21659  {
21660  Utilities->CallLogPop(323);
21661  return(true);
21662  }
21663  }
21664  if(SecondPair.first > -1)
21665  {
21666  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
21667  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21668  {
21669  Utilities->CallLogPop(324);
21670  return(true);
21671  }
21672  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21673  {
21674  Utilities->CallLogPop(325);
21675  return(true);
21676  }
21677  }
21678  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
21679  3, TrainID)))
21680  {
21681  Utilities->CallLogPop(2000);
21682  return(true);
21683  }
21684  Utilities->CallLogPop(326);
21685  return(false);
21686 }
21687 
21688 // ---------------------------------------------------------------------------
21689 
21690 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21691 /*
21692  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
21693  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21694  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21695  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21696  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21697  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21698  Each of these is examined in turn for each route element in the relevant position.
21699 */
21700 {
21701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
21702  "," + AnsiString(DiagonalLinkNumber));
21703  TPrefDirElement TempPrefDirElement;
21704  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21705 
21706  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
21707  if(FirstPair.first > -1)
21708  {
21709  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
21710  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21711  {
21712  Utilities->CallLogPop(2010);
21713  return(true);
21714  }
21715  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21716  {
21717  Utilities->CallLogPop(2011);
21718  return(true);
21719  }
21720  }
21721  if(SecondPair.first > -1)
21722  {
21723  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
21724  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21725  {
21726  Utilities->CallLogPop(2012);
21727  return(true);
21728  }
21729  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21730  {
21731  Utilities->CallLogPop(2013);
21732  return(true);
21733  }
21734  }
21735  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
21736  if(FirstPair.first > -1)
21737  {
21738  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
21739  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21740  {
21741  Utilities->CallLogPop(2014);
21742  return(true);
21743  }
21744  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21745  {
21746  Utilities->CallLogPop(2015);
21747  return(true);
21748  }
21749  }
21750  if(SecondPair.first > -1)
21751  {
21752  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
21753  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21754  {
21755  Utilities->CallLogPop(2016);
21756  return(true);
21757  }
21758  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21759  {
21760  Utilities->CallLogPop(2017);
21761  return(true);
21762  }
21763  }
21764  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
21765  if(FirstPair.first > -1)
21766  {
21767  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
21768  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21769  {
21770  Utilities->CallLogPop(2018);
21771  return(true);
21772  }
21773  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21774  {
21775  Utilities->CallLogPop(2019);
21776  return(true);
21777  }
21778  }
21779  if(SecondPair.first > -1)
21780  {
21781  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
21782  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21783  {
21784  Utilities->CallLogPop(2020);
21785  return(true);
21786  }
21787  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21788  {
21789  Utilities->CallLogPop(2021);
21790  return(true);
21791  }
21792  }
21793  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
21794  if(FirstPair.first > -1)
21795  {
21796  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
21797  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21798  {
21799  Utilities->CallLogPop(2022);
21800  return(true);
21801  }
21802  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21803  {
21804  Utilities->CallLogPop(2023);
21805  return(true);
21806  }
21807  }
21808  if(SecondPair.first > -1)
21809  {
21810  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
21811  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21812  {
21813  Utilities->CallLogPop(2024);
21814  return(true);
21815  }
21816  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21817  {
21818  Utilities->CallLogPop(2025);
21819  return(true);
21820  }
21821  }
21822  Utilities->CallLogPop(2026);
21823  return(false);
21824 }
21825 
21826 // ---------------------------------------------------------------------------
21827 
21828 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9743
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19923
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1330
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TTrack::MarkOneLengthandSpeed
void MarkOneLengthandSpeed(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:10148
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:12532
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:12505
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:439
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4825
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:573
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5700
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:14050
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:83
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1746
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:214
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:815
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:428
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:20518
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:92
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10582
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:20929
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1384
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:807
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:14574
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:825
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:437
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:14090
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Uses 'ChangeTransparentColour' method to change each graphic in turn.
Definition: GraphicUnit.cpp:3974
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:805
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:287
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7512
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:19885
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:103
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1726
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:730
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5852
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7413
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5879
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1540
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:593
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1687
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:67
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1978
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:933
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:11035
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:623
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:21690
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:439
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1717
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:71
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:614
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2886
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:558
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:6032
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8440
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
Definition: TrackUnit.h:1550
TUtilities::RedLowFlag
bool RedLowFlag
Sets Red = low values for heatmaps.
Definition: Utilities.h:77
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:459
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:652
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:20356
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:585
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:13829
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7898
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrackElement::StationEntryStopLinkPos3
int StationEntryStopLinkPos3
Definition: TrackUnit.h:153
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:11060
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9693
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:15223
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:17770
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1140
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:20718
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1667
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:13633
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:161
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4575
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3724
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1564
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8255
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:445
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:196
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1045
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4735
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1344
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6696
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:11810
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3600
Unused
@ Unused
Definition: TrackUnit.h:66
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrack::OneStationLongEnoughForSplit
bool OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:11284
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1343
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:21203
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2919
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7884
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:228
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:21400
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:581
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1725
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1562
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1654
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:210
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:780
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:443
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:821
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3324
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16985
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TUtilities::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
< used to send no platforms warning once only
Definition: Utilities.h:87
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8732
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13895
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:809
Simple
@ Simple
Definition: TrackUnit.h:66
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:79
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2935
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:732
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1045
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:20466
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1411
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:14146
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3951
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1784
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5992
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:314
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:745
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:382
TTrack::SetNonStationStopLinkEntryPosses
void SetNonStationStopLinkEntryPosses(int Caller)
similar to SetStationEntryStopLinkPosses but for non-station named elements
Definition: TrackUnit.cpp:10798
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:15094
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12546
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:577
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:633
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7913
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:95
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:66
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:20826
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7659
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:614
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:575
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:11140
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:588
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen (as viewpoint moves down [railway moves up] this offset i...
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1566
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1528
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrack::IsElementDefaultLengthAndSpeed
bool IsElementDefaultLengthAndSpeed(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
True if track at link positions [0] & [1] if FirstTrack true, else that at [2] & [3] in TrackElement ...
Definition: TrackUnit.cpp:10486
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:753
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:587
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:811
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1420
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6280
End
@ End
Definition: TrackUnit.h:76
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1568
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:625
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:9086
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:570
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:11249
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1058
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:305
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:748
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:817
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:125
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:812
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3925
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:876
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:232
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:445
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:66
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9827
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1039
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:19873
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:509
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear
bool SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:18543
TAllRoutes::TAllRoutesVectorIterator
std::vector< TOneRoute >::iterator TAllRoutesVectorIterator
Definition: TrackUnit.h:1681
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1090
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1691
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7927
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:675
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:7105
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:650
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:230
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:9125
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:19858
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:67
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:829
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:75
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14863
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:14600
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:235
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:929
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:65
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4660
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1928
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:98
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:437
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:789
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:94
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:12013
TUtilities::NoPlatsMessageSent
bool NoPlatsMessageSent
Definition: Utilities.h:85
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:20671
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4921
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:161
TRailGraphics::HeatMapGraphic
Graphics::TBitmap * HeatMapGraphic
Definition: GraphicUnit.h:1034
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1947
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:799
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:767
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:565
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1750
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:470
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:660
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:12258
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:21306
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1056
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2903
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1574
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:16098
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7540
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8922
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7619
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5903
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:697
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:329
TOneRoute::QuitAllRecursiveSearchesFlag
bool QuitAllRecursiveSearchesFlag
< limit to the number of elements searched in attempting to find a route in on leg
Definition: TrackUnit.h:1554
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:688
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:19378
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1346
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:876
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:14234
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:13369
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1692
TTrack::LengthandSpeedMarker
void LengthandSpeedMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9862
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:87
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1744
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
gives a delay od Msec value;
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:46
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:795
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13862
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:715
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:19504
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3701
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:14553
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:12301
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1830
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:941
TRailGraphics::GetHeatMapColor
void GetHeatMapColor(int Caller, float value, int *red, int *green, int *blue)
Definition: GraphicUnit.cpp:4923
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:584
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6086
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1028
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:13682
Under
@ Under
Definition: TrackUnit.h:76
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:829
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:629
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2958
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12558
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12877
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:434
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:135
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:56
Lead
@ Lead
Definition: TrackUnit.h:76
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:125
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5951
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1864
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:14801
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6163
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:895
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:558
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:262
TRailGraphics::ChangeForegroundColour2
void ChangeForegroundColour2(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
New function to do the same as the above but with fewer pixel changes - for use in LoadSession to avo...
Definition: GraphicUnit.cpp:3674
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5743
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:18790
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6677
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:86
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:101
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1375
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9621
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:714
TTrack::Up
@ Up
Definition: TrackUnit.h:614
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:831
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:588
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:11263
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1522
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:380
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8889
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1685
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:761
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:206
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:19591
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1674
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:66
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6563
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:833
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8835
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7568
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10555
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:76
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:575
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:593
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:797
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:20160
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1598
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:13732
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:12197
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4744
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:573
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:11235
TGraphicElement::Width
int Width
Definition: TrackUnit.h:441
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:21075
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:21290
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:19986
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:803
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:848
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:662
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:553
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:15632
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:662
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4233
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2419
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:695
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9761
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks, bool PerformNameSearch)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2161
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:13500
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:795
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:968
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5927
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:21373
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1566
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1556
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7266
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1069
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1071
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:8099
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:19683
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:663
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7641
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:67
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5548
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:829
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:14623
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:621
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:12109
Parapet
@ Parapet
Definition: TrackUnit.h:67
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:55
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:19832
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:121
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:275
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9430
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:19656
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:829
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:20694
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:801
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:249
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1074
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:740
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:17340
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:137
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:208
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:12329
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:13427
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1324
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:19619
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:551
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1383
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:876
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1414
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:20842
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:18443
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1724
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1661
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8409
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:591
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:128
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:206
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:20334
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:214
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3038
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:10323
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6457
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:159
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:590
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:161
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:167
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:809
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2639
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:204
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1659
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:8063
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:13215
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13993
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:589
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1528
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:11172
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8798
IDInt
Definition: TrackUnit.h:500
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:3014
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:21341
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4548
TDisplay
Definition: DisplayUnit.h:50
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10922
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5291
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:922
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:443
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:21438
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1154
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9544
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:573
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:97
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8010
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1325
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:229
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:141
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:14303
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:785
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:212
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:15429
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1729
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:186
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:130
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7978
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:635
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:911
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1539
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1665
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TOneRoute::RouteSearchLimitOneLeg
static const int RouteSearchLimitOneLeg
< limit to the total number of elements searched in attempting to find a route
Definition: TrackUnit.h:1552
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1675
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4843
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9370
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:759
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:16791
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1353
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:437
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:14729
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1331
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:14504
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:66
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:20407
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:12180
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4255
Trail
@ Trail
Definition: TrackUnit.h:76
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:19568
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9603
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1900
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:41
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:18333
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:66
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1065
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7857
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3801
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6183
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:14401
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:593
TTrack::ThisLocationLongEnoughForSplit
bool ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement, int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
checks if the track that the train is on is long enough for a split, returns false if not,...
Definition: TrackUnit.cpp:11555
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9650
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:13258
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:579
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:716
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:437
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1054
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:795
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3418
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:441
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1559
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:88
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:717
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:742
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1723
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:269
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:355
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:21520
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:14198
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1043
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1530
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1047
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:791
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:905
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4804
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:20306
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1756
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8936
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:699
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:125
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:813
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:233
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:710
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1385
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:19710
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:717
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:21357
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:583
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1910
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4786
Connection
@ Connection
Definition: TrackUnit.h:76
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3778
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
Definition: TrackUnit.h:1731
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:18146
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:12487
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:13076
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8862
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:12459
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1052
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:20616
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:20572
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7339
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:567
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11838
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:736
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1412
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:18355
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5971
TTrack::OneLengthOrSpeedHeatMapColour
void OneLengthOrSpeedHeatMapColour(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
Heatmap function for a single trackelement.
Definition: TrackUnit.cpp:9909
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:263
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:155
TTrackElement::StationEntryStopLinkPos4
int StationEntryStopLinkPos4
Used for track at platforms ( 1 & 2) and non-station named locations (1 - 4) to mark the train front ...
Definition: TrackUnit.h:153
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:437
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10609
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:575
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:738
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:753
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:19845
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4953
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2814
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7938
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3180
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:132
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:18304
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:631
TTrack::LengthOrSpeedHeatMap
void LengthOrSpeedHeatMap(int Caller, bool Length, TDisplay *Disp)
Heatmap function for all track elements - unused.
Definition: TrackUnit.cpp:9883
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen (as viewpoint moves to the right [railway moves left] t...
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14993
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:319
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:775
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:696
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1107
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12397
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1325
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:657
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:667
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:12637
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:437
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:100
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1526
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:201
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8985
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:524
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1808
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9167
TTrack::LengthHeatMapFlag
bool LengthHeatMapFlag
true when plotting a length heatmap
Definition: TrackUnit.h:763
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:99
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:726
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:14700
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:21325
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:613
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1382
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4566
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:819
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4677
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7801
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2005
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1060
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6603
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7596
Platform
@ Platform
Definition: TrackUnit.h:66
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1414
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:214
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:669
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::SpeedHeatMapFlag
bool SpeedHeatMapFlag
true when plotting a speed heatmap
Definition: TrackUnit.h:765
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:783
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:755
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4702
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:793
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1669
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1067
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12429
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8360
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1338
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9801
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1041
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:12074
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1815
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:111
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1528
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:17212
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7784
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:823
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:169
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1530
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:618
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6620
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3678
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:101
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:115
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:586
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:759
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:12000
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:17628
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:683
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:305
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:627
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1073
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:90
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:690
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:827
RouteCall
@ RouteCall
Definition: TrackUnit.h:1331
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12571
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
Definition: TextUnit.cpp:269
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:97
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:76
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:673
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:20888
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:267
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:745
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:12029
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:11004
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:678
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:536
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:204
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
True if another train on LinkPos track of element at TrackPos, whether bridge or not,...
Definition: TrackUnit.cpp:11967
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6521
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:161
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:16134
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:751
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12583
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1387
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1663
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1580
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:575
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10995
Bridge
@ Bridge
Definition: TrackUnit.h:66
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1325
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:76
Buffers
@ Buffers
Definition: TrackUnit.h:66
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:18062
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:105
CrossConn
@ CrossConn
Definition: TrackUnit.h:76
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:12595
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4614
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:12518
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852
TTrack::OneNonStationLongEnoughForSplit
bool OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName)
As below but here allow points & crossovers.
Definition: TrackUnit.cpp:11391